├── common └── constants.go ├── rpc ├── testagent │ ├── auth_test.proto │ └── tls_test.proto ├── cloudagent │ ├── network │ │ ├── moc_cloudagent_networkinterface.go │ │ ├── macpool │ │ │ └── moc_cloudagent_macpool.proto │ │ ├── vippool │ │ │ └── moc_cloudagent_vippool.proto │ │ ├── publicipaddress │ │ │ └── moc_cloudagent_publicipaddress.proto │ │ ├── logicalnetwork │ │ │ └── moc_cloudagent_logicalnetwork.proto │ │ ├── networksecuritygroup │ │ │ └── moc_cloudagent_networksecuritygroup.proto │ │ ├── virtualnetwork │ │ │ └── moc_cloudagent_virtualnetwork.proto │ │ ├── networkinterface │ │ │ └── moc_cloudagent_networkinterface.proto │ │ └── loadbalancer │ │ │ └── moc_cloudagent_loadbalancer.proto │ ├── security │ │ ├── authentication │ │ │ └── moc_cloudagent_authentication.proto │ │ ├── keyvault │ │ │ ├── moc_cloudagent_keyvault.proto │ │ │ ├── secret │ │ │ │ └── moc_cloudagent_secret.proto │ │ │ └── key │ │ │ │ └── moc_cloudagent_key.proto │ │ ├── roleassignment │ │ │ └── moc_cloudagent_roleassignment.proto │ │ ├── role │ │ │ └── moc_cloudagent_role.proto │ │ ├── certificate │ │ │ └── moc_cloudagent_certificate.proto │ │ └── identity │ │ │ └── moc_cloudagent_identity.proto │ ├── cloud │ │ ├── location │ │ │ └── moc_cloudagent_location.proto │ │ ├── subscription │ │ │ └── moc_cloudagent_subscription.proto │ │ ├── group │ │ │ └── moc_cloudagent_group.proto │ │ ├── cluster │ │ │ └── moc_cloudagent_cluster.proto │ │ ├── etcdcluster │ │ │ ├── moc_cloudagent_etcdcluster.proto │ │ │ └── etcdserver │ │ │ │ └── moc_cloudagent_etcdserver.proto │ │ ├── node │ │ │ └── moc_cloudagent_node.proto │ │ ├── zone │ │ │ └── moc_cloudagent_zone.proto │ │ ├── controlplane │ │ │ └── moc_cloudagent_controlplane.proto │ │ └── kubernetes │ │ │ └── moc_cloudagent_kubernetes.proto │ ├── admin │ │ ├── credentialmonitor │ │ │ └── moc_cloudagent_credentialmonitor.proto │ │ └── logging │ │ │ └── moc_cloudagent_logging.proto │ ├── compute │ │ ├── baremetalmachine │ │ │ └── moc_cloudagent_baremetalmachine.proto │ │ ├── virtualmachineimage │ │ │ └── moc_cloudagent_virtualmachineimage.proto │ │ ├── virtualmachinescaleset │ │ │ └── moc_cloudagent_virtualmachinescaleset.proto │ │ ├── placementgroup │ │ │ └── moc_cloudagent_placementgroup.proto │ │ ├── baremetalhost │ │ │ └── moc_cloudagent_baremetalhost.proto │ │ ├── availabilityset │ │ │ └── moc_cloudagent_availabilityset.proto │ │ └── galleryimage │ │ │ └── moc_cloudagent_galleryimage.proto │ └── storage │ │ ├── container │ │ └── moc_cloudagent_container.proto │ │ └── virtualharddisk │ │ └── moc_cloudagent_virtualharddisk.proto ├── common │ ├── admin │ │ ├── version │ │ │ └── moc_common_version.proto │ │ ├── validation │ │ │ └── moc_common_validation.proto │ │ ├── debug │ │ │ └── moc_common_debug.proto │ │ ├── recovery │ │ │ └── moc_common_recovery.proto │ │ ├── health │ │ │ └── moc_common_health.proto │ │ └── logging │ │ │ └── moc_common_logging.proto │ ├── moc_common_storageinfo.proto │ ├── moc_common_notification.proto │ ├── moc_common_nodeinfo.proto │ ├── moc_common_security.proto │ └── moc_common_networkcommon.proto ├── mocguestagent │ ├── admin │ │ └── health │ │ │ └── moc_mocguestagent_health.proto │ ├── security │ │ └── certificate │ │ │ └── moc_mocguestagent_certificate.proto │ └── compute │ │ └── virtualmachine │ │ └── moc_mocguestagent_virtualmachine.proto ├── nodeagent │ ├── security │ │ ├── authentication │ │ │ └── moc_nodeagent_authentication.proto │ │ ├── keyvault │ │ │ ├── moc_nodeagent_keyvault.proto │ │ │ ├── secret │ │ │ │ └── moc_nodeagent_secret.proto │ │ │ └── key │ │ │ │ └── moc_nodeagent_key.proto │ │ ├── identity │ │ │ └── moc_nodeagent_identity.proto │ │ └── certificate │ │ │ └── moc_nodeagent_certificate.proto │ ├── admin │ │ └── credentialmonitor │ │ │ └── moc_nodeagent_credentialmonitor.proto │ ├── storage │ │ ├── moc_nodeagent_virtualharddisk_test.go │ │ ├── container │ │ │ └── moc_nodeagent_container.proto │ │ ├── sharedfolder │ │ │ └── moc_nodeagent_sharedfolder.proto │ │ └── virtualharddisk │ │ │ └── moc_nodeagent_virtualharddisk.proto │ ├── network │ │ ├── loadbalancer │ │ │ └── moc_nodeagent_loadbalancer.proto │ │ ├── logicalnetwork │ │ │ └── moc_nodeagent_logicalnetwork.proto │ │ ├── virtualnetworkinterface │ │ │ └── moc_nodeagent_virtualnetworkinterface.proto │ │ └── virtualnetwork │ │ │ └── moc_nodeagent_virtualnetwork.proto │ ├── node │ │ └── host │ │ │ └── moc_nodeagent_host.proto │ └── compute │ │ ├── placementgroup │ │ └── moc_nodeagent_placementgroup.proto │ │ ├── availabilityset │ │ └── moc_nodeagent_availabilityset.proto │ │ └── virtualmachinescaleset │ │ └── moc_nodeagent_virtualmachinescaleset.proto ├── guestagent │ └── admin │ │ └── exec │ │ └── moc_guestagent_exec.proto ├── mochostagent │ ├── admin │ │ └── exec │ │ │ └── moc_mochostagent_exec.proto │ └── compute │ │ └── virtualmachine │ │ └── moc_mochostagent_virtualmachine.proto ├── ipamagent │ └── ipaddressmanager │ │ ├── moc_ipaddress_ipaddressmanager.proto │ │ └── ipaddress │ │ └── moc_ipaddress_ipaddress.proto ├── baremetalhostagent │ └── agent │ │ └── moc_baremetalhostagent.proto └── lbagent │ └── agent │ └── moc_lbagent_agent.proto ├── azure-pipelines.yml ├── pkg ├── convert │ └── convert.go ├── logging │ ├── redirectstderr_linux.go │ ├── redirectstderr_windows.go │ ├── logger.go │ ├── logger_test.go │ ├── filetransfer.go │ └── loggingRedirect.go ├── errors │ └── codes │ │ ├── codes_test.go │ │ ├── codes.go │ │ └── codes_string.go ├── path │ └── path.go ├── intercept │ └── interceptors.go ├── fs │ ├── fs_darwin.go │ ├── fs_linux.go │ └── fs_windows.go ├── certs │ ├── mock │ │ └── mock_certificateAuthority.go │ └── cert_utils.go ├── diagnostics │ └── context.go ├── tags │ ├── tags.go │ └── tags_test.go ├── providerid │ └── providerid.go ├── validations │ ├── proxy_validation.go │ └── proxy_validation_test.go ├── auth │ ├── mock │ │ └── auth_mock.go │ ├── auth_env_test.go │ ├── pkv.go │ └── auth_env.go ├── marshal │ └── marshal_test.go └── config │ ├── config_test.go │ └── config.go ├── .github ├── workflows │ ├── autoupdate.yaml │ └── codeql.yml └── dependabot.yml ├── CODE_OF_CONDUCT.md ├── .gdn └── .gdntsa ├── .golangci.yml ├── NOTICE.md ├── README.md ├── Makefile ├── go.mod ├── gen.sh ├── .pipelines ├── build.yaml └── static.yaml └── SECURITY.md /common/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package wssdcommon 5 | 6 | import ( 7 | "time" 8 | ) 9 | 10 | const ( 11 | DefaultServerContextTimeout = 120 * time.Second 12 | ) 13 | -------------------------------------------------------------------------------- /rpc/testagent/auth_test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = "github.com/microsoft/moc/rpc/testagent"; 3 | package testagent; 4 | 5 | 6 | message Holla { 7 | string Name = 1; 8 | } 9 | 10 | service HollaAgent { 11 | rpc PingHolla(Holla) returns (Holla); 12 | } -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - main 3 | 4 | schedules: 5 | - cron: "0 0 * * *" 6 | displayName: Moc - main branch - daily build 7 | branches: 8 | include: 9 | - main 10 | 11 | jobs: 12 | - template: .pipelines/build.yaml 13 | - template: .pipelines/static.yaml 14 | -------------------------------------------------------------------------------- /rpc/testagent/tls_test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = "github.com/microsoft/moc/rpc/testagent"; 3 | package testagent; 4 | 5 | 6 | message Hello { 7 | string Name = 1; 8 | } 9 | 10 | service HelloAgent { 11 | rpc PingHello(Hello) returns (Hello); 12 | } 13 | -------------------------------------------------------------------------------- /pkg/convert/convert.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package convert 4 | 5 | // ToStringPtr 6 | func ToStringPtr(val string) *string { 7 | return &val 8 | } 9 | 10 | // ToInt32Ptr 11 | func ToInt32Ptr(val int32) *int32 { 12 | return &val 13 | } 14 | -------------------------------------------------------------------------------- /rpc/cloudagent/network/moc_cloudagent_networkinterface.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | func (m *NetworkInterface) GetPrimaryIpConfiguration() *IpConfiguration { 4 | if m != nil { 5 | for _, ipConfig := range m.IpConfigurations { 6 | if ipConfig.Primary { 7 | return ipConfig 8 | } 9 | } 10 | } 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/autoupdate.yaml: -------------------------------------------------------------------------------- 1 | name: autoupdate 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | autoupdate: 8 | name: autoupdate 9 | runs-on: ubuntu-18.04 10 | steps: 11 | - uses: docker://chinthakagodawita/autoupdate-action:v1 12 | env: 13 | GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' 14 | -------------------------------------------------------------------------------- /pkg/logging/redirectstderr_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package logging 5 | 6 | import ( 7 | "os" 8 | "syscall" 9 | ) 10 | 11 | func RedirectStdErr(file *os.File) { 12 | syscall.Dup3(int(file.Fd()), int(os.Stderr.Fd()), 0) //nolint:golint,errcheck 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /pkg/errors/codes/codes_test.go: -------------------------------------------------------------------------------- 1 | package codes 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestErrorMessages(t *testing.T) { 8 | // Test that all error codes have a corresponding message 9 | maxMocCode := int(_maxCode) - 1 10 | for i := 0; i <= maxMocCode; i++ { 11 | mocCode := MocCode(i) 12 | if !mocCode.IsValid() { 13 | t.Errorf("MocCode %d is not valid, ensure that it has been assigned a string and error code", mocCode) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.gdn/.gdntsa: -------------------------------------------------------------------------------- 1 | { 2 | "codebaseName": "moc_master_One", 3 | "notificationAliases": [ 4 | "akshcidev@microsoft.com" 5 | ], 6 | "codebaseAdmins": [ 7 | "REDMOND\\madhanm", 8 | "REDMOND\\natarajr" 9 | ], 10 | "instanceUrl": "https://msazure.visualstudio.com/defaultcollection", 11 | "projectName": "One", 12 | "areaPath": "One\\AKSArc\\s360", 13 | "iterationPath": "One\\Custom", 14 | "allTools": true, 15 | "template": "TFSMSAzure" 16 | } 17 | -------------------------------------------------------------------------------- /rpc/common/admin/version/moc_common_version.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | 8 | message VersionRequest {} 9 | 10 | message VersionResponse { 11 | string version = 1; 12 | string mocversion = 2; 13 | string error = 3; 14 | } 15 | 16 | service VersionAgent { 17 | rpc Get(VersionRequest) returns (VersionResponse) {} 18 | } 19 | -------------------------------------------------------------------------------- /rpc/common/admin/validation/moc_common_validation.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | 8 | enum ValidationOperation { 9 | VALIDATE = 0; 10 | } 11 | 12 | message ValidationRequest{} 13 | 14 | message ValidationResponse { 15 | string Error = 1; 16 | } 17 | 18 | service ValidationAgent { 19 | rpc Invoke(ValidationRequest) returns (ValidationResponse) {} 20 | } 21 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | 2 | run: 3 | timeout: 15m 4 | tests: false # Exclude test files from linting 5 | 6 | # Linter options and descriptions: https://golangci-lint.run/usage/linters/ 7 | linters: 8 | enable: 9 | - errcheck 10 | - govet 11 | - ineffassign 12 | - staticcheck 13 | disable: 14 | # Disabling these two default linters for now as their checks are not a priority 15 | - gosimple 16 | - unused 17 | 18 | linters-settings: 19 | staticcheck: 20 | checks: 21 | - all 22 | - -SA1019 # Ignore pkg deprecation warnings from staticcheck -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" -------------------------------------------------------------------------------- /pkg/path/path.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | // Package path has code for working with windows paths. 5 | package path 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path/filepath" 11 | ) 12 | 13 | // CheckPath verifies that the path provided exists and returns the absolute path. 14 | func CheckPath(path string) error { 15 | cleanPath := filepath.Clean(path) 16 | fileInfo, err := os.Stat(cleanPath) 17 | if err != nil { 18 | return err 19 | } 20 | if !fileInfo.IsDir() { 21 | return fmt.Errorf("%s is not a directory", path) 22 | } 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /pkg/intercept/interceptors.go: -------------------------------------------------------------------------------- 1 | // Package intercept provides gRPC interceptors for MOCStack clients. 2 | package intercept 3 | 4 | import ( 5 | "context" 6 | 7 | "github.com/microsoft/moc/pkg/errors" 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | // NewErrorParsingInterceptor transforms grpc errors to moc errors 12 | func NewErrorParsingInterceptor() grpc.UnaryClientInterceptor { 13 | return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { 14 | err := invoker(ctx, method, req, reply, cc, opts...) 15 | return errors.ParseGRPCError(err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/fs/fs_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package fs 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | func Chmod(path string, mode os.FileMode) error { 11 | return os.Chmod(path, mode) 12 | } 13 | 14 | func ChmodRecursiveAdmin(path string) error { 15 | err := filepath.Walk(path, func(path string, info os.FileInfo, walkErr error) error { 16 | if walkErr != nil { 17 | return walkErr 18 | } 19 | 20 | if walkErr = Chmod(path, 0700); walkErr != nil { 21 | return walkErr 22 | } 23 | return nil 24 | }) 25 | if err != nil { 26 | return err 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /pkg/fs/fs_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package fs 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | func Chmod(path string, mode os.FileMode) error { 11 | return os.Chmod(path, mode) 12 | } 13 | 14 | func ChmodRecursiveAdmin(path string) error { 15 | err := filepath.Walk(path, func(path string, info os.FileInfo, walkErr error) error { 16 | if walkErr != nil { 17 | return walkErr 18 | } 19 | 20 | if walkErr = Chmod(path, 0700); walkErr != nil { 21 | return walkErr 22 | } 23 | return nil 24 | }) 25 | if err != nil { 26 | return err 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /rpc/common/moc_common_storageinfo.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the Apache v2.0 license. 4 | 5 | syntax = "proto3"; 6 | option go_package = "github.com/microsoft/moc/rpc/common"; 7 | package moc; 8 | import "moc_common_common.proto"; 9 | 10 | 11 | message StorageContainerInfo { 12 | Capacity capacity = 1; 13 | Latency latency = 2; 14 | string node = 3; 15 | string zone = 4; 16 | Status status = 7; 17 | } 18 | 19 | message Capacity { 20 | uint64 totalBytes = 1; 21 | uint64 availableBytes = 2; 22 | } 23 | 24 | message Latency { 25 | uint64 iops = 1; 26 | } 27 | 28 | enum VirtualHardDiskOperation { 29 | UPLOAD = 0; 30 | } 31 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | This repository incorporates material as listed below or described in the code. 2 | 3 | Copyright © Microsoft Corporation. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /rpc/mocguestagent/admin/health/moc_mocguestagent_health.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/mocguestagent/admin"; 6 | package moc.mocguestagent.admin; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message HealthRequest{ 12 | uint32 timeoutSeconds = 1; 13 | } 14 | 15 | message HealthResponse { 16 | google.protobuf.BoolValue Result = 1; 17 | string Error = 2; 18 | HealthState State = 3; 19 | google.protobuf.BoolValue CertificateNeedsRenewal = 4; 20 | } 21 | 22 | service HealthAgent { 23 | rpc CheckHealth(HealthRequest) returns (HealthResponse) {} 24 | } 25 | 26 | -------------------------------------------------------------------------------- /rpc/common/admin/debug/moc_common_debug.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | import "moc_common_common.proto"; 8 | 9 | enum DebugOperation { 10 | DEBUGSERVER = 0; 11 | STACKTRACE = 1; 12 | } 13 | 14 | message DebugRequest{ 15 | // Operation Type 16 | DebugOperation OBSOLETE_OperationType = 1 [deprecated=true]; 17 | // Artibraty data 18 | string Data = 2; 19 | ProviderAccessOperation OperationType = 3; 20 | } 21 | 22 | message DebugResponse { 23 | string Result = 1; 24 | } 25 | 26 | service DebugAgent { 27 | rpc Invoke(DebugRequest) returns (DebugResponse) {} 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/authentication/moc_nodeagent_authentication.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_nodeagent_identity.proto"; 10 | import "moc_common_common.proto"; 11 | 12 | message AuthenticationRequest { 13 | Identity Identity = 1; 14 | } 15 | 16 | message AuthenticationResponse { 17 | string Token = 1 [(sensitive) = true]; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | service AuthenticationAgent { 23 | rpc Login(AuthenticationRequest) returns (AuthenticationResponse) {} 24 | } 25 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/authentication/moc_cloudagent_authentication.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_cloudagent_identity.proto"; 10 | import "moc_common_common.proto"; 11 | 12 | message AuthenticationRequest { 13 | Identity Identity = 1; 14 | } 15 | 16 | message AuthenticationResponse { 17 | string Token = 1 [(sensitive) = true]; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | service AuthenticationAgent { 23 | rpc Login(AuthenticationRequest) returns (AuthenticationResponse) {} 24 | } 25 | -------------------------------------------------------------------------------- /rpc/guestagent/admin/exec/moc_guestagent_exec.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/guestagent/admin"; 6 | package moc.guestagent.admin; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message ExecRequest { 13 | repeated Exec Execs = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message ExecResponse { 18 | repeated Exec Execs = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message Exec { 24 | string command = 1; 25 | string output = 2; 26 | Status status = 3; 27 | } 28 | 29 | service ExecAgent { 30 | rpc Invoke (ExecRequest) returns (ExecResponse) {} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /rpc/mochostagent/admin/exec/moc_mochostagent_exec.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/mochostagent/admin"; 6 | package moc.mochostagent.admin; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message ExecRequest { 13 | repeated Exec Execs = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message ExecResponse { 18 | repeated Exec Execs = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message Exec { 24 | string command = 1; 25 | string output = 2; 26 | Status status = 3; 27 | } 28 | 29 | service ExecAgent { 30 | rpc Invoke (ExecRequest) returns (ExecResponse) {} 31 | } 32 | -------------------------------------------------------------------------------- /pkg/logging/redirectstderr_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package logging 5 | 6 | import ( 7 | "os" 8 | "syscall" 9 | ) 10 | 11 | var ( 12 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 13 | procSetStdHandle = kernel32.MustFindProc("SetStdHandle") 14 | ) 15 | 16 | func setStdHandle(stdhandle int32, handle syscall.Handle) error { 17 | r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0) 18 | if r0 == 0 { 19 | if e1 != 0 { 20 | return error(e1) 21 | } 22 | return syscall.EINVAL 23 | } 24 | return nil 25 | } 26 | 27 | func RedirectStdErr(file *os.File) { 28 | err := setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(file.Fd())) 29 | if err != nil { 30 | } 31 | os.Stderr = file 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/location/moc_cloudagent_location.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.location; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message LocationRequest { 12 | repeated Location Locations = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message LocationResponse { 17 | repeated Location Locations = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message Location { 23 | string name = 1; 24 | string id = 2; 25 | Status status = 3; 26 | Tags tags = 4; 27 | } 28 | 29 | service LocationAgent { 30 | rpc Invoke(LocationRequest) returns (LocationResponse) {} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /rpc/cloudagent/admin/credentialmonitor/moc_cloudagent_credentialmonitor.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/admin"; 6 | package moc.cloudagent.admin; 7 | import "moc_common_common.proto"; 8 | 9 | enum CertificateStatus { 10 | Single = 0; 11 | Overlap = 1; 12 | } 13 | 14 | message CredentialMonitorRequest { 15 | CredentialMonitor CredentialMonitor = 1; 16 | } 17 | 18 | message CredentialMonitorResponse { 19 | CredentialMonitor CredentialMonitor = 1; 20 | string Error = 2; 21 | } 22 | 23 | message CredentialMonitor { 24 | string certificate = 1 [(sensitive) = true]; 25 | CertificateStatus status = 2; 26 | } 27 | 28 | service CredentialMonitorAgent { 29 | rpc Get(CredentialMonitorRequest) returns (CredentialMonitorResponse) {} 30 | } 31 | -------------------------------------------------------------------------------- /rpc/nodeagent/admin/credentialmonitor/moc_nodeagent_credentialmonitor.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/admin"; 6 | package moc.nodeagent.admin; 7 | import "moc_common_common.proto"; 8 | 9 | enum CertificateStatus { 10 | Single = 0; 11 | Overlap = 1; 12 | } 13 | 14 | message CredentialMonitorRequest { 15 | CredentialMonitor CredentialMonitor = 1; 16 | } 17 | 18 | message CredentialMonitorResponse { 19 | CredentialMonitor CredentialMonitor = 1; 20 | string Error = 2; 21 | } 22 | 23 | message CredentialMonitor { 24 | string certificate = 1 [(sensitive) = true]; 25 | CertificateStatus status = 2; 26 | } 27 | 28 | service CredentialMonitorAgent { 29 | rpc Get(CredentialMonitorRequest) returns (CredentialMonitorResponse) {} 30 | } 31 | -------------------------------------------------------------------------------- /rpc/common/admin/recovery/moc_common_recovery.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | 10 | enum Operation { 11 | BACKUP = 0; 12 | RESTORE = 1; 13 | } 14 | 15 | message RecoveryRequest{ 16 | Operation OperationType = 1; 17 | // Path to back to or restore from. Can be a relative path for registry 18 | string Path = 2; 19 | // Config file path. Must be on hard disk. 20 | string ConfigFilePath = 3; 21 | // Type of data store 22 | string StoreType = 4; 23 | } 24 | 25 | message RecoveryResponse { 26 | google.protobuf.BoolValue Result = 2; 27 | string Error = 3; 28 | } 29 | 30 | service RecoveryAgent { 31 | rpc Invoke(RecoveryRequest) returns (RecoveryResponse) {} 32 | } 33 | 34 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/subscription/moc_cloudagent_subscription.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.subscription; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message SubscriptionRequest { 12 | repeated Subscription Subscriptions = 1; 13 | Operation OperationType = 2; 14 | // SubPostOperation PostOperationType = 3; 15 | } 16 | 17 | message SubscriptionResponse { 18 | repeated Subscription Subscriptions = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message Subscription { 24 | string name = 1; 25 | string id = 2; 26 | Status status = 3; 27 | Tags tags = 4; 28 | } 29 | 30 | service SubscriptionAgent { 31 | rpc Invoke(SubscriptionRequest) returns (SubscriptionResponse) {} 32 | } 33 | 34 | -------------------------------------------------------------------------------- /rpc/nodeagent/storage/moc_nodeagent_virtualharddisk_test.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "net/url" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/microsoft/moc/pkg/redact" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestRedactedError_VHD(t *testing.T) { 15 | // Has issue with ampersand (&); queryescape is needed to pass 16 | uri := url.QueryEscape(`https://test.blob.core.windowssdfsdf.net/testvhd/test.vhdx?sp=r&st=2025-01-31T10:33:25Z&se=2025-01-31T18:33:25Z&spr=https&sv=2022-11-02&sr=b&sig=dfdf`) 17 | 18 | azureProp := AzureGalleryImageProperties{SasURI: uri} 19 | propertiesJson, e := json.Marshal(azureProp) 20 | if e != nil { 21 | t.Error(e) 22 | } 23 | vhd := VirtualHardDisk{Name: "test", Source: string(propertiesJson)} 24 | err := errors.New(uri + " : Unable to reach host") 25 | redact.RedactError(&vhd, &err) 26 | assert.False(t, strings.Contains(err.Error(), uri), err.Error()) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/keyvault/moc_nodeagent_keyvault.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_nodeagent_secret.proto"; 11 | 12 | message KeyVaultRequest { 13 | repeated KeyVault KeyVaults = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message KeyVaultResponse { 18 | repeated KeyVault KeyVaults = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message KeyVault { 24 | string name = 1; 25 | string id = 2; 26 | repeated Secret Secrets = 3; 27 | string groupName = 4; 28 | Status status = 5; 29 | Entity entity = 6; 30 | Tags tags = 7; 31 | } 32 | 33 | service KeyVaultAgent { 34 | rpc Invoke(KeyVaultRequest) returns (KeyVaultResponse) {} 35 | } 36 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/group/moc_cloudagent_group.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.group; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | enum SubPostOperation { 12 | CREATE = 0; 13 | UPDATE = 1; 14 | LOCK = 2; 15 | } 16 | 17 | message GroupRequest { 18 | repeated Group Groups = 1; 19 | Operation OperationType = 2; 20 | SubPostOperation PostOperationType = 3; 21 | } 22 | 23 | message GroupResponse { 24 | repeated Group Groups = 1; 25 | google.protobuf.BoolValue Result = 2; 26 | string Error = 3; 27 | } 28 | 29 | message Group { 30 | string name = 1; 31 | string id = 2; 32 | Status status = 3; 33 | string locationName = 4; 34 | Tags tags = 5; 35 | } 36 | 37 | service GroupAgent { 38 | rpc Invoke(GroupRequest) returns (GroupResponse) {} 39 | } 40 | 41 | -------------------------------------------------------------------------------- /rpc/common/moc_common_notification.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common"; 6 | 7 | package moc; 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message Notification { 12 | // Name of the entity sending notification 13 | string entityName = 1; 14 | // Type of operation that happened on the entity 15 | Operation operation = 2; 16 | // Optional: Additional message that the entity would like to send 17 | string message = 3; 18 | // Name of the parent Entity 19 | string parentEntityName = 4; 20 | // Optional flag to specify if the notification is async 21 | bool async = 5; 22 | //Unique identifier for the notification 23 | string id = 6; 24 | } 25 | 26 | message NotificationResponse { 27 | repeated Notification notifications = 1; 28 | google.protobuf.BoolValue Result = 2; 29 | string Error = 3; 30 | } 31 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/keyvault/moc_cloudagent_keyvault.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_cloudagent_secret.proto"; 11 | 12 | message KeyVaultRequest { 13 | repeated KeyVault KeyVaults = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message KeyVaultResponse { 18 | repeated KeyVault KeyVaults = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message KeyVault { 24 | string name = 1; 25 | string id = 2; 26 | repeated Secret Secrets = 3; 27 | string groupName = 4; 28 | Status status = 5; 29 | string locationName = 10; 30 | Tags tags = 11; 31 | } 32 | 33 | service KeyVaultAgent { 34 | rpc Invoke(KeyVaultRequest) returns (KeyVaultResponse) {} 35 | } 36 | -------------------------------------------------------------------------------- /rpc/common/admin/health/moc_common_health.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | 8 | import "google/protobuf/empty.proto"; 9 | import "google/protobuf/wrappers.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_nodeinfo.proto"; 12 | 13 | message HealthRequest{ 14 | uint32 timeoutSeconds = 1; 15 | } 16 | 17 | message HealthResponse { 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | HealthState State = 4; 21 | bool Rebooted = 5; 22 | } 23 | 24 | message AgentInfoResponse{ 25 | NodeInfo node = 1; 26 | google.protobuf.BoolValue Result = 2; 27 | string Error = 3; 28 | string deploymentId = 4; 29 | } 30 | 31 | service HealthAgent { 32 | rpc CheckHealth(HealthRequest) returns (HealthResponse) {} 33 | rpc GetAgentInfo(google.protobuf.Empty) returns (AgentInfoResponse) {} 34 | } 35 | 36 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/keyvault/secret/moc_nodeagent_secret.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message SecretRequest { 12 | repeated Secret Secrets = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message SecretResponse { 17 | repeated Secret Secrets = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message Secret { 23 | string name = 1; 24 | string id = 2; 25 | string filename = 3; 26 | string value = 4 [(sensitive) = true]; 27 | string vaultId = 5; 28 | string vaultName = 6; 29 | string groupName = 7; 30 | Status status = 8; 31 | Entity entity = 9; 32 | Tags tags = 10; 33 | } 34 | 35 | service SecretAgent { 36 | rpc Invoke(SecretRequest) returns (SecretResponse) {} 37 | } 38 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/keyvault/secret/moc_cloudagent_secret.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message SecretRequest { 12 | repeated Secret Secrets = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message SecretResponse { 17 | repeated Secret Secrets = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message Secret { 23 | string name = 1; 24 | string id = 2; 25 | string filename = 3; 26 | string value = 4 [(sensitive) = true]; 27 | string vaultId = 5; 28 | string vaultName = 6; 29 | string groupName = 7; 30 | Status status = 8; 31 | string locationName = 10; 32 | Tags tags = 11; 33 | } 34 | 35 | service SecretAgent { 36 | rpc Invoke(SecretRequest) returns (SecretResponse) {} 37 | } 38 | -------------------------------------------------------------------------------- /rpc/nodeagent/network/loadbalancer/moc_nodeagent_loadbalancer.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/network"; 6 | package moc.nodeagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message LoadBalancerRequest { 13 | repeated LoadBalancer LoadBalancers = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message LoadBalancerResponse { 18 | repeated LoadBalancer LoadBalancers = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message LoadBalancer { 24 | string name = 1; 25 | string id = 2; 26 | string frontendip = 4; 27 | string backendpoolname = 5; 28 | string networkid = 6; 29 | Status status = 8; 30 | Entity entity = 9; 31 | Tags tags = 10; 32 | } 33 | 34 | service LoadBalancerAgent { 35 | rpc Invoke(LoadBalancerRequest) returns (LoadBalancerResponse) {} 36 | } 37 | 38 | -------------------------------------------------------------------------------- /rpc/ipamagent/ipaddressmanager/moc_ipaddress_ipaddressmanager.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/ipamagent"; 6 | package moc.ipaddressmanager; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message IPAddressManagerRequest { 13 | repeated IPAddressManager IPAddressManagers = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message IPAddressManagerResponse { 18 | repeated IPAddressManager IPAddressManagers = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message IPAddressManager { 24 | string name = 1; 25 | string id = 2; 26 | Status status = 8; 27 | } 28 | 29 | service IPAddressManagerAgent { 30 | rpc Get(IPAddressManagerRequest) returns (IPAddressManagerResponse) {} 31 | rpc Create(IPAddressManagerRequest) returns (IPAddressManagerResponse) {} 32 | rpc Delete(IPAddressManagerRequest) returns (IPAddressManagerResponse) {} 33 | } 34 | 35 | -------------------------------------------------------------------------------- /rpc/baremetalhostagent/agent/moc_baremetalhostagent.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/baremetalhostagent"; 6 | 7 | package moc.baremetalhostagent; 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message BareMetalHostOperatingSystemConfiguration { 12 | string computerName = 1; 13 | string customData = 2 [(sensitive) = true]; 14 | } 15 | 16 | message BareMetalHost { 17 | string name = 1; 18 | string id = 2; 19 | BareMetalHostOperatingSystemConfiguration os = 3; 20 | Status status = 4; 21 | Entity entity = 5; 22 | Tags tags = 6; 23 | } 24 | 25 | message BareMetalHostRequest { 26 | BareMetalHost bareMetalHost = 1; 27 | } 28 | 29 | message BareMetalHostResponse { 30 | BareMetalHost bareMetalHost = 1; 31 | google.protobuf.BoolValue Result = 2; 32 | string Error = 3; 33 | } 34 | 35 | service BareMetalHostAgent { 36 | rpc CreateOrUpdate(BareMetalHostRequest) returns (BareMetalHostResponse) {} 37 | } 38 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/identity/moc_nodeagent_identity.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message IdentityRequest { 12 | repeated Identity Identitys = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message IdentityResponse { 17 | repeated Identity Identitys = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message Identity { 23 | string name = 1; 24 | string id = 2; 25 | string resourceGroup = 3; 26 | string password = 4 [(sensitive) = true]; 27 | string token = 5 [(sensitive) = true]; 28 | string certificate = 6 [(sensitive) = true]; 29 | Status status = 7; 30 | Entity entity = 8; 31 | Tags tags = 9; 32 | int64 tokenExpiry = 13; 33 | ClientType clientType = 14; 34 | } 35 | 36 | service IdentityAgent { 37 | rpc Invoke(IdentityRequest) returns (IdentityResponse) {} 38 | } 39 | -------------------------------------------------------------------------------- /rpc/ipamagent/ipaddressmanager/ipaddress/moc_ipaddress_ipaddress.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/ipamagent"; 6 | package moc.ipaddress; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message IPAddressRequest { 13 | repeated IPAddress IPAddresss = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message IPAddressResponse { 18 | repeated IPAddress IPAddresss = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | enum IPAddressFamily { 24 | IPV4 = 0; 25 | IPV6 = 1; 26 | } 27 | 28 | message IPAddress { 29 | string name = 1; 30 | string id = 2; 31 | string address = 3; 32 | string cidr = 4; 33 | int32 prefixLength = 5; 34 | Status status = 8; 35 | } 36 | 37 | 38 | service IPAddressAgent { 39 | rpc Get(IPAddressRequest) returns (IPAddressResponse) {} 40 | rpc Create(IPAddressRequest) returns (IPAddressResponse) {} 41 | rpc Delete(IPAddressRequest) returns (IPAddressResponse) {} 42 | } 43 | 44 | -------------------------------------------------------------------------------- /rpc/nodeagent/node/host/moc_nodeagent_host.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/node"; 6 | package moc.nodeagent.host; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message HostRequest { 12 | Host Host = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message HostResponse { 17 | Host Host = 1; 18 | string RootCACertificate = 2 [(sensitive) = true]; 19 | string IntermediateCACertificate = 3 [(sensitive) = true]; 20 | google.protobuf.BoolValue Result = 4; 21 | string Error = 5; 22 | } 23 | 24 | enum HostState { 25 | Unknown = 0; 26 | Active = 1; 27 | Inactive = 2; 28 | Poweroff = 3; 29 | } 30 | 31 | message Host { 32 | string name = 1; 33 | string id = 2; 34 | Status status = 3; 35 | string certificate = 4 [(sensitive) = true]; 36 | int32 port = 5; 37 | int32 authorizerPort = 6; 38 | HostState runningState = 7; 39 | Tags tags = 8; 40 | } 41 | 42 | service MocHostAgent { 43 | rpc Invoke(HostRequest) returns (HostResponse) {} 44 | } 45 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/cluster/moc_cloudagent_cluster.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.cluster; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_cloudagent_node.proto"; 11 | 12 | message ClusterResponse { 13 | repeated Cluster Clusters = 1; 14 | google.protobuf.BoolValue Result = 2; 15 | string Error = 3; 16 | } 17 | 18 | message Cluster { 19 | string name = 1; 20 | string id = 2; 21 | string fqdn = 3; 22 | Status status = 4; 23 | bool UserOwned = 5; 24 | bool IsLocalCluster = 6; 25 | string domain = 7; 26 | repeated moc.cloudagent.node.Node Nodes = 8; 27 | string locationName = 9; 28 | Tags tags = 10; 29 | } 30 | 31 | 32 | service ClusterAgent { 33 | rpc LoadCluster(Cluster) returns (ClusterResponse) {} 34 | rpc UnloadCluster(Cluster) returns (ClusterResponse) {} 35 | rpc GetCluster(Cluster) returns (ClusterResponse) {} 36 | rpc GetNodes(Cluster) returns (moc.cloudagent.node.NodeResponse) {} 37 | } 38 | 39 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/etcdcluster/moc_cloudagent_etcdcluster.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.etcd; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message EtcdClusterRequest { 12 | repeated EtcdCluster EtcdClusters = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message EtcdClusterResponse { 17 | repeated EtcdCluster EtcdClusters = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message EtcdCluster { 23 | string id = 1; 24 | string name = 2; 25 | string locationName = 3; 26 | string groupName = 4; 27 | // etcd ca certificate that works as RoT for client and peer connections 28 | string caCertificate = 5 [(sensitive) = true]; 29 | // etcd ca key associated with the ca certificate 30 | string caKey = 6 [(sensitive) = true]; 31 | Status status = 7; 32 | } 33 | 34 | service EtcdClusterAgent { 35 | rpc Invoke(EtcdClusterRequest) returns (EtcdClusterResponse) {} 36 | } 37 | 38 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/roleassignment/moc_cloudagent_roleassignment.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_security.proto"; 11 | 12 | message RoleAssignmentRequest { 13 | repeated RoleAssignment roleAssignments = 2; 14 | Operation OperationType = 3; 15 | } 16 | 17 | message RoleAssignmentResponse { 18 | repeated RoleAssignment roleAssignments = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message RoleAssignment { 24 | string name = 1; 25 | string id = 2; 26 | // Name of role to be applied 27 | string roleName = 3; 28 | // Scope to which role is applied 29 | Scope scope = 4; 30 | // Name of identity to be assigned to 31 | string identityName = 5; 32 | Status status = 6; 33 | Tags tags = 7; 34 | } 35 | 36 | service RoleAssignmentAgent { 37 | rpc Invoke(RoleAssignmentRequest) returns (RoleAssignmentResponse) {} 38 | } 39 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/etcdcluster/etcdserver/moc_cloudagent_etcdserver.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.etcd; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message EtcdServerRequest { 12 | repeated EtcdServer EtcdServers = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message EtcdServerResponse { 17 | repeated EtcdServer EtcdServers = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message EtcdServer { 23 | string id = 1; 24 | string name = 2; 25 | string etcdClusterName = 3; 26 | string clusterId = 4; 27 | string locationName = 5; 28 | string groupName = 6; 29 | // fqdn is the fqdn, hostname, or ip address that this EtcdServer will 30 | // advertise on 31 | string fqdn = 7; 32 | // etcd client port to listen on 33 | uint32 clientPort = 8; 34 | Status status = 9; 35 | } 36 | 37 | service EtcdServerAgent { 38 | rpc Invoke(EtcdServerRequest) returns (EtcdServerResponse) {} 39 | } 40 | 41 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/node/moc_cloudagent_node.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.node; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_nodeinfo.proto"; 11 | 12 | message NodeRequest { 13 | repeated Node Nodes = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message NodeResponse { 18 | repeated Node Nodes = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | enum NodeState { 24 | Unknown = 0; 25 | Active = 1; 26 | Inactive = 2; 27 | Poweroff = 3; 28 | } 29 | 30 | message Node { 31 | string name = 1; 32 | string id = 2; 33 | string fqdn = 3; 34 | Status status = 4; 35 | string locationName = 5; 36 | string certificate = 6 [(sensitive) = true]; 37 | int32 port = 7; 38 | int32 authorizerPort = 8; 39 | NodeState runningState = 9; 40 | moc.common.NodeInfo info = 10; 41 | Tags tags = 11; 42 | } 43 | 44 | service NodeAgent { 45 | rpc Invoke(NodeRequest) returns (NodeResponse) {} 46 | } 47 | 48 | -------------------------------------------------------------------------------- /rpc/cloudagent/admin/logging/moc_cloudagent_logging.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/admin"; 6 | package moc.cloudagent.admin; 7 | 8 | service LogAgent { 9 | rpc Get(LogRequest) returns (stream LogFileResponse) {} 10 | rpc Set(SetRequest) returns (SetResponse) {}; 11 | rpc GetLevel(GetRequest) returns (GetResponse) {} 12 | } 13 | 14 | enum GetLogType { 15 | All = 0; 16 | Cloud = 1; 17 | Node = 2; 18 | } 19 | 20 | message LogRequest { 21 | GetLogType type = 1; 22 | string location = 2; 23 | } 24 | 25 | message LogFileResponse { 26 | bytes file = 1; 27 | bool done = 2; 28 | string error = 3; 29 | string filename = 4; 30 | } 31 | 32 | message SetResponse { 33 | string error = 1; 34 | } 35 | 36 | message SetRequest { 37 | int32 verbositylevel = 1; 38 | bool include_nodeagents = 2; 39 | } 40 | 41 | message GetRequest {} 42 | 43 | message GetResponse { 44 | string error =1; 45 | string level =2; 46 | } -------------------------------------------------------------------------------- /rpc/nodeagent/storage/container/moc_nodeagent_container.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/storage"; 6 | package moc.nodeagent.storage; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "google/protobuf/empty.proto"; 11 | import "moc_common_notification.proto"; 12 | import "moc_common_storageinfo.proto"; 13 | 14 | enum ContainerType { 15 | UNKNOWN = 0; 16 | SAN = 1; 17 | CSV = 2; 18 | SMB = 3; 19 | DAS = 4; 20 | } 21 | 22 | message ContainerRequest { 23 | repeated Container Containers = 1; 24 | Operation OperationType = 2; 25 | } 26 | 27 | message ContainerResponse { 28 | repeated Container Containers = 1; 29 | google.protobuf.BoolValue Result = 2; 30 | string Error = 3; 31 | } 32 | 33 | message Container { 34 | string name = 1; 35 | string id = 2; 36 | string path = 4 [(sensitive) = true]; 37 | Status status = 5; 38 | Entity entity = 6; 39 | Tags tags = 7; 40 | StorageContainerInfo info = 8; 41 | } 42 | 43 | service ContainerAgent { 44 | rpc Invoke(ContainerRequest) returns (ContainerResponse) {} 45 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /rpc/nodeagent/storage/sharedfolder/moc_nodeagent_sharedfolder.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/storage"; 6 | package moc.nodeagent.storage; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_notification.proto"; 11 | import "google/protobuf/empty.proto"; 12 | 13 | message SharedFolderRequest { 14 | repeated SharedFolder SharedFolderSystems = 1; 15 | Operation OperationType = 2; 16 | } 17 | 18 | message SharedFolderResponse { 19 | repeated SharedFolder SharedFolderSystems = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message SharedFolder { 25 | string name = 1; 26 | string id = 2; 27 | string containerName = 3; 28 | string folderName = 4; 29 | bool readOnly = 5; 30 | string path = 6 [(sensitive) = true]; 31 | string virtualmachineName = 7; 32 | string guestMountPath = 8; 33 | string mountTag = 9; 34 | Status status = 10; 35 | Entity entity = 11; 36 | Tags tags = 12; 37 | } 38 | 39 | service SharedFolderAgent { 40 | rpc Invoke(SharedFolderRequest) returns (SharedFolderResponse) {} 41 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 42 | } 43 | -------------------------------------------------------------------------------- /rpc/nodeagent/compute/placementgroup/moc_nodeagent_placementgroup.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/compute"; 6 | package moc.nodeagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_nodeagent_availabilityset.proto"; 11 | 12 | enum PlacementGroupType { 13 | Affinity = 0; 14 | AntiAffinity = 1 ; 15 | StrictAntiAffinity = 2; 16 | } 17 | 18 | enum PlacementGroupScope { 19 | Server = 0; 20 | Zone = 1 ; 21 | } 22 | 23 | message PlacementGroupRequest { 24 | repeated PlacementGroup PlacementGroups = 1; 25 | Operation OperationType = 2; 26 | } 27 | 28 | message PlacementGroupResponse { 29 | repeated PlacementGroup PlacementGroups = 1; 30 | google.protobuf.BoolValue Result = 2; 31 | string Error = 3; 32 | } 33 | 34 | message PlacementGroup { 35 | string name = 1; 36 | string id = 2; 37 | string groupName = 3; 38 | PlacementGroupType type = 4; 39 | PlacementGroupScope scope = 5; 40 | ZoneConfiguration zones = 6; 41 | Entity entity = 7; 42 | Status status = 8; 43 | repeated VirtualMachineReference virtualMachines = 9; 44 | } 45 | 46 | service PlacementGroupAgent { 47 | rpc Invoke(PlacementGroupRequest) returns (PlacementGroupResponse) {} 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Generating ProtoBuf 3 | 4 | ## Prerequisites 5 | 6 | Go must be installed. 7 | 8 | ## Steps 9 | Simply run: 10 | 11 | make generate 12 | make all 13 | 14 | This will automatically handle pulling down the remaining dependencies (e.g. `protoc`), generating the `*.pb.go` 15 | files and placing those files in the repository. After that, you can use git (e.g. `git status`) to review the 16 | changes. 17 | 18 | # Contributing 19 | 20 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 21 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 22 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 23 | 24 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 25 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 26 | provided by the bot. You will only need to do this once across all repos using our CLA. 27 | 28 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 29 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 30 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 31 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/zone/moc_cloudagent_zone.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.zone; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message ZoneRequest { 12 | repeated Zone Zones = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message ZoneResponse { 17 | repeated Zone Zones = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message ZonePrecheckRequest { 23 | repeated Zone Zones = 1; 24 | } 25 | 26 | message ZonePrecheckResponse { 27 | // The precheck result: true if the precheck criteria is passed; otherwise, false 28 | google.protobuf.BoolValue Result = 1; 29 | 30 | // The error message if the precheck is not passed; otherwise, empty string 31 | string Error = 2; 32 | } 33 | 34 | message Zone { 35 | string name = 1; 36 | string id = 2; 37 | string locationName = 3; 38 | repeated string nodes = 5; 39 | Status status = 6; 40 | } 41 | 42 | service ZoneAgent { 43 | rpc Invoke(ZoneRequest) returns (ZoneResponse) {} 44 | 45 | // Prechecks whether the system is able to create specified zone (but does not actually create them). 46 | rpc Precheck(ZonePrecheckRequest) returns (ZonePrecheckResponse) {} 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /pkg/logging/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package logging 5 | 6 | import ( 7 | "fmt" 8 | "github.com/go-logr/logr" 9 | ) 10 | 11 | type Logger interface { 12 | Info(msg string, keysAndValues ...interface{}) 13 | Error(err error, msg string, keysAndValues ...interface{}) 14 | } 15 | 16 | type LogrLogger struct { 17 | logger logr.Logger 18 | } 19 | 20 | // DefaultLogger is a simple logger that writes to stdout 21 | type DefaultLogger struct{} 22 | 23 | // NewLogrLogger creates a new LogrLogger instance that wraps a logr.Logger 24 | func NewLogrLogger(logger logr.Logger) *LogrLogger { 25 | return &LogrLogger{ 26 | logger: logger, 27 | } 28 | } 29 | 30 | // Info logs an info level message 31 | func (l *LogrLogger) Info(msg string, keysAndValues ...interface{}) { 32 | l.logger.Info(msg, keysAndValues...) 33 | } 34 | 35 | // Error logs an error level message 36 | func (l *LogrLogger) Error(err error, msg string, keysAndValues ...interface{}) { 37 | l.logger.Error(err, msg, keysAndValues...) 38 | } 39 | 40 | func (d *DefaultLogger) Info(msg string, keysAndValues ...interface{}) { 41 | fmt.Printf("INFO: %s ", msg) 42 | fmt.Println(keysAndValues...) 43 | } 44 | 45 | func (d *DefaultLogger) Error(err error, msg string, keysAndValues ...interface{}) { 46 | fmt.Printf("ERROR: %s ", msg) 47 | fmt.Println(keysAndValues...) 48 | if err != nil { 49 | fmt.Printf("Error: %s\n", err.Error()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the Apache v2.0 license. 3 | GOCMD=GO111MODULE=on GOARCH=amd64 go 4 | GOBUILD=$(GOCMD) build -v #-mod=vendor 5 | GOTEST=$(GOCMD) test -v 6 | GOHOSTOS=$(strip $(shell $(GOCMD) env get GOHOSTOS)) 7 | MOCKGEN=$(shell command -v mockgen 2> /dev/null) 8 | GOPATH_BIN := $(shell go env GOPATH)/bin 9 | 10 | # Private repo workaround 11 | export GOPRIVATE = github.com/microsoft 12 | # Active module mode, as we use go modules to manage dependencies 13 | export GO111MODULE=on 14 | 15 | # 16 | PKG := 17 | 18 | all: format test 19 | 20 | .PHONY: tidy 21 | tidy: 22 | go mod tidy 23 | 24 | format: 25 | gofmt -s -w rpc/ pkg/ 26 | 27 | bootstrap: 28 | GOOS="linux" go get -u google.golang.org/grpc@v1.59.0 29 | GOOS="linux" go install github.com/golang/protobuf/protoc-gen-go@v1.3.2 30 | 31 | test: unittest 32 | 33 | unittest: 34 | $(GOTEST) ./pkg/... 35 | 36 | generate: bootstrap 37 | (./gen.sh) 38 | 39 | pipeline: bootstrap 40 | (./gen.sh -c) 41 | 42 | 43 | ## Install mockgen golang bin 44 | install-mockgen: 45 | ifeq ($(MOCKGEN),) 46 | go install github.com/golang/mock/mockgen@v1.6.0 47 | endif 48 | MOCKGEN=$(shell command -v mockgen 2> /dev/null) 49 | 50 | mocks: 51 | go mod download github.com/golang/mock 52 | go get github.com/golang/mock@v1.6.0 53 | go generate ./... 54 | 55 | 56 | golangci-lint: 57 | $(GOCMD) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 58 | $(GOPATH_BIN)/golangci-lint run --config .golangci.yml 59 | -------------------------------------------------------------------------------- /rpc/common/admin/logging/moc_common_logging.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common/admin"; 6 | package moc.common.admin; 7 | import "google/protobuf/wrappers.proto"; 8 | 9 | enum VerboseLevel { 10 | Min_Level = 0; 11 | Max_Level = 9; 12 | } 13 | 14 | message LogRotateRequest { 15 | LogRotation logRotation = 1; 16 | } 17 | 18 | message LogRotateResponse { 19 | bool Result = 1; 20 | string Error = 2; 21 | } 22 | 23 | message LogRotation { 24 | int32 minutes = 1; 25 | int32 size = 2; 26 | bool enableTime = 3; 27 | bool enableSize = 4; 28 | bool disableTime = 5; 29 | bool disableSize = 6; 30 | int32 limit = 7; 31 | } 32 | 33 | message LogRequest {} 34 | 35 | message LogFileResponse { 36 | bytes file = 1; 37 | google.protobuf.BoolValue done = 2; 38 | string error = 3; 39 | } 40 | 41 | service LogAgent { 42 | rpc Get(LogRequest) returns (stream LogFileResponse) {} 43 | rpc Rotate(LogRotateRequest) returns (LogRotateResponse) {} 44 | rpc Set(SetRequest) returns (SetResponse) {}; 45 | rpc GetLevel(GetRequest) returns (GetResponse) {} 46 | } 47 | 48 | message SetResponse { 49 | string error = 1; 50 | } 51 | 52 | message SetRequest { 53 | int32 verbositylevel = 1; 54 | } 55 | 56 | message GetRequest {} 57 | 58 | message GetResponse { 59 | string error =1; 60 | string level =2; 61 | } 62 | -------------------------------------------------------------------------------- /rpc/nodeagent/network/logicalnetwork/moc_nodeagent_logicalnetwork.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/network"; 6 | package moc.nodeagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "google/protobuf/empty.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_networkcommon.proto"; 12 | import "moc_common_notification.proto"; 13 | 14 | message LogicalNetworkRequest { 15 | repeated LogicalNetwork LogicalNetworks = 1; 16 | Operation OperationType = 2; 17 | } 18 | 19 | message LogicalNetworkResponse { 20 | repeated LogicalNetwork LogicalNetworks = 1; 21 | google.protobuf.BoolValue Result = 2; 22 | string Error = 3; 23 | } 24 | 25 | message LogicalNetwork { 26 | string name = 1; 27 | string id = 2; 28 | repeated LogicalNetworkIpam ipams = 3; 29 | Status status = 4; 30 | Entity entity = 5; 31 | Tags tags = 6; 32 | } 33 | 34 | message LogicalSubnet { 35 | string name = 1; 36 | string id = 2; 37 | string addressPrefix = 3; 38 | repeated Route routes = 4; 39 | IPAllocationMethod allocation = 5; 40 | uint32 vlan = 6; 41 | Dns dns = 7; 42 | } 43 | message LogicalNetworkIpam { 44 | string type = 1; 45 | repeated LogicalSubnet subnets = 2; 46 | } 47 | 48 | service LogicalNetworkAgent { 49 | rpc Invoke(LogicalNetworkRequest) returns (LogicalNetworkResponse) {} 50 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 51 | } 52 | 53 | -------------------------------------------------------------------------------- /rpc/mocguestagent/security/certificate/moc_mocguestagent_certificate.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/mocguestagent/security"; 6 | package moc.mocguestagent.security; 7 | import "google/protobuf/wrappers.proto"; 8 | import "google/protobuf/empty.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message CertificateRequest { 12 | repeated Certificate Certificates = 1; 13 | } 14 | 15 | message CertificateResponse { 16 | google.protobuf.BoolValue Result = 1; 17 | string Error = 2; 18 | } 19 | 20 | message Certificate { 21 | string name = 1; 22 | string id = 2; 23 | int64 notBefore = 3; 24 | int64 notAfter = 4; 25 | string certificate = 5 [(sensitive) = true]; 26 | Status status = 6; 27 | Entity entity = 7; 28 | Tags tags = 8; 29 | } 30 | 31 | message CSRRequest { 32 | repeated CertificateSigningRequest CSRs = 1; 33 | } 34 | 35 | message CertificateSigningRequest { 36 | string name = 1; 37 | string csr = 2 [(sensitive) = true]; 38 | string oldCertificate = 3 [(sensitive) = true]; 39 | Status status = 4; 40 | string caName = 5; 41 | int64 validity = 6; 42 | } 43 | 44 | message RenewCSRResponse { 45 | CertificateSigningRequest csr = 1; 46 | google.protobuf.BoolValue Result = 2; 47 | string Error = 3; 48 | } 49 | 50 | service CertificateAgent { 51 | rpc GetRenewCSR(google.protobuf.Empty) returns (RenewCSRResponse) {} 52 | rpc RotateCertificate(CertificateRequest) returns (CertificateResponse) {} 53 | } 54 | -------------------------------------------------------------------------------- /rpc/cloudagent/network/macpool/moc_cloudagent_macpool.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message MacPoolRequest { 12 | repeated MacPool MacPools = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message MacPoolResponse { 17 | repeated MacPool MacPools = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message MacPoolPrecheckRequest { 23 | repeated MacPool MacPools = 1; 24 | } 25 | 26 | message MacPoolPrecheckResponse { 27 | // The precheck result: true if the precheck criteria is passed; otherwise, false 28 | google.protobuf.BoolValue Result = 1; 29 | 30 | // The error message if the precheck is not passed; otherwise, empty string 31 | string Error = 2; 32 | } 33 | 34 | message MacRange { 35 | string startMacAddress = 1; 36 | string endMacAddress = 2; 37 | } 38 | 39 | message MacPool { 40 | string name = 1; 41 | string id = 2; 42 | MacRange range = 3; 43 | string locationName = 4; 44 | Status status = 6; 45 | Tags tags = 7; 46 | } 47 | 48 | service MacPoolAgent { 49 | rpc Invoke(MacPoolRequest) returns (MacPoolResponse) {} 50 | 51 | // Prechecks whether the system is able to create specified MAC pools (but does not actually create them). 52 | rpc Precheck(MacPoolPrecheckRequest) returns (MacPoolPrecheckResponse) {} 53 | } 54 | 55 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/microsoft/moc 2 | 3 | go 1.24.0 4 | 5 | toolchain go1.24.7 6 | 7 | require ( 8 | github.com/go-logr/logr v1.4.3 9 | github.com/golang-jwt/jwt/v4 v4.5.2 10 | github.com/golang/mock v1.6.0 11 | github.com/golang/protobuf v1.5.4 12 | github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb 13 | github.com/jmespath/go-jmespath v0.4.0 14 | github.com/pkg/errors v0.9.1 15 | github.com/stretchr/testify v1.8.3 16 | go.uber.org/multierr v1.11.0 17 | google.golang.org/grpc v1.76.0 18 | gopkg.in/yaml.v3 v3.0.1 19 | ) 20 | 21 | require ( 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/pmezard/go-difflib v1.0.0 // indirect 24 | golang.org/x/net v0.42.0 // indirect 25 | golang.org/x/sys v0.34.0 // indirect 26 | golang.org/x/text v0.31.0 // indirect 27 | google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect 28 | google.golang.org/protobuf v1.36.10 // indirect 29 | ) 30 | 31 | replace ( 32 | github.com/golang/mock => github.com/golang/mock v1.6.0 33 | github.com/stretchr/testify => github.com/stretchr/testify v1.8.3 34 | go.opentelemetry.io/proto/otlp => go.opentelemetry.io/proto/otlp v0.19.0 35 | golang.org/x/crypto => golang.org/x/crypto v0.37.0 36 | golang.org/x/image => golang.org/x/image v0.10.0 37 | golang.org/x/net => golang.org/x/net v0.17.0 38 | golang.org/x/sys => golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 39 | gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.2.8 40 | ) 41 | 42 | // Brought in by google.golang.org/grpc bump to 1.56.3, but uses CC-BY-SA-3.0 copyleft license 43 | exclude github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19 44 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/baremetalmachine/moc_cloudagent_baremetalmachine.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_cloudagent_virtualmachine.proto"; 11 | 12 | message BareMetalMachineRequest { 13 | repeated BareMetalMachine BareMetalMachines = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message BareMetalMachineResponse { 18 | repeated BareMetalMachine BareMetalMachines = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message BareMetalMachineStorageConfiguration { 24 | string imageReference = 2; 25 | } 26 | 27 | message BareMetalMachineOperatingSystemConfiguration { 28 | string computerName = 1; 29 | UserConfiguration administrator = 2; 30 | repeated UserConfiguration users = 3; 31 | string customData = 4 [(sensitive) = true]; 32 | repeated SSHPublicKey publicKeys = 5; 33 | LinuxConfiguration linuxConfiguration = 6; 34 | } 35 | 36 | message BareMetalMachine { 37 | string name = 1; 38 | string id = 2; 39 | BareMetalMachineStorageConfiguration storage = 3; 40 | BareMetalMachineOperatingSystemConfiguration os = 4; 41 | SecurityConfiguration security = 5; 42 | string fqdn = 6; 43 | string groupName = 7; 44 | Status status = 8; 45 | string locationName = 9; 46 | Tags tags = 10; 47 | } 48 | 49 | service BareMetalMachineAgent { 50 | rpc Invoke(BareMetalMachineRequest) returns (BareMetalMachineResponse) {} 51 | } 52 | -------------------------------------------------------------------------------- /pkg/certs/mock/mock_certificateAuthority.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/microsoft/moc/pkg/certs (interfaces: Revocation) 3 | 4 | // Package mock_certs is a generated GoMock package. 5 | package mock_certs 6 | 7 | import ( 8 | x509 "crypto/x509" 9 | reflect "reflect" 10 | 11 | gomock "github.com/golang/mock/gomock" 12 | ) 13 | 14 | // MockRevocation is a mock of Revocation interface. 15 | type MockRevocation struct { 16 | ctrl *gomock.Controller 17 | recorder *MockRevocationMockRecorder 18 | } 19 | 20 | // MockRevocationMockRecorder is the mock recorder for MockRevocation. 21 | type MockRevocationMockRecorder struct { 22 | mock *MockRevocation 23 | } 24 | 25 | // NewMockRevocation creates a new mock instance. 26 | func NewMockRevocation(ctrl *gomock.Controller) *MockRevocation { 27 | mock := &MockRevocation{ctrl: ctrl} 28 | mock.recorder = &MockRevocationMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use. 33 | func (m *MockRevocation) EXPECT() *MockRevocationMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // IsRevoked mocks base method. 38 | func (m *MockRevocation) IsRevoked(arg0 *x509.Certificate) error { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "IsRevoked", arg0) 41 | ret0, _ := ret[0].(error) 42 | return ret0 43 | } 44 | 45 | // IsRevoked indicates an expected call of IsRevoked. 46 | func (mr *MockRevocationMockRecorder) IsRevoked(arg0 interface{}) *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRevoked", reflect.TypeOf((*MockRevocation)(nil).IsRevoked), arg0) 49 | } 50 | -------------------------------------------------------------------------------- /rpc/common/moc_common_nodeinfo.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common"; 6 | package moc.common; 7 | 8 | import "moc_common_common.proto"; 9 | import "moc_common_computecommon.proto"; 10 | 11 | enum OsRegistrationState { 12 | notRegistered = 0; 13 | registered = 1; 14 | } 15 | 16 | message OsRegistrationStatus { 17 | OsRegistrationState status = 1; 18 | } 19 | 20 | message Processor { 21 | string name = 1; 22 | uint32 cores = 2; 23 | string speed = 3; 24 | ProcessorType type = 4; 25 | bool virtualization = 5; 26 | uint32 logicalprocessors = 6; 27 | bool hypervisorpresent = 7; 28 | string manufacturer = 8; 29 | Architecture architecture = 9; 30 | } 31 | 32 | message PhysicalMemory { 33 | uint64 sizeBytes = 1; 34 | } 35 | 36 | message HostGPU { 37 | string id = 1; 38 | string name = 2; 39 | uint64 partitionSizeMB = 3; 40 | AssignmentType assignment = 4; 41 | } 42 | 43 | message OperatingSystem { 44 | uint64 operatingsystemsku = 1; 45 | OperatingSystemType ostype = 2; 46 | string osversion = 3; 47 | OsRegistrationStatus osRegistrationStatus = 4; 48 | } 49 | 50 | message NodeInfo { 51 | string name = 1; 52 | string id = 2; 53 | Resources capability = 3; 54 | Resources availability = 4; 55 | OperatingSystemType ostype = 6; 56 | Status status = 7; 57 | int64 uptime = 8; 58 | OperatingSystem osInfo = 9; 59 | } 60 | 61 | message Resources { 62 | reserved 3; 63 | reserved 4; 64 | reserved 6; 65 | Processor processor = 1; 66 | PhysicalMemory memory = 2; 67 | VirtualMachineCapabilities vmCapabilities = 5; 68 | repeated HostGPU hostGPUs = 7; 69 | } -------------------------------------------------------------------------------- /rpc/mocguestagent/compute/virtualmachine/moc_mocguestagent_virtualmachine.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/mocguestagent/compute"; 6 | package moc.mocguestagent.compute; 7 | 8 | import "google/protobuf/empty.proto"; 9 | import "google/protobuf/wrappers.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_computecommon.proto"; 12 | import "moc_common_notification.proto"; 13 | 14 | message VirtualMachineRunCommandRequest { 15 | VirtualMachineRunCommandScriptSource Source = 1; 16 | repeated VirtualMachineRunCommandInputParameter RunCommandInputParameters = 2; 17 | string OperationID = 3; 18 | string RunAsUser = 4 [(sensitive) = true]; 19 | string RunAsPassword = 5 [(sensitive) = true]; 20 | } 21 | 22 | message VirtualMachineCommandResultRequest { 23 | string OperationID = 1; 24 | } 25 | 26 | message VirtualMachineRunCommandResponse { 27 | VirtualMachineRunCommandInstanceView InstanceView = 1; 28 | string OperationID = 2; 29 | } 30 | 31 | message UpdateAgentRequest { 32 | bytes AgentBinary = 1; 33 | string MocVersion = 2; 34 | } 35 | 36 | message UpdateAgentResponse { 37 | google.protobuf.BoolValue Result = 1; 38 | string Error = 2; 39 | } 40 | 41 | service VirtualMachineAgent { 42 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 43 | rpc RunCommand(VirtualMachineRunCommandRequest) returns (VirtualMachineRunCommandResponse) {} 44 | rpc GetCommandResult(VirtualMachineCommandResultRequest) returns (VirtualMachineRunCommandResponse) {} 45 | rpc UpdateAgent(UpdateAgentRequest) returns (UpdateAgentResponse) {} 46 | } -------------------------------------------------------------------------------- /rpc/cloudagent/network/vippool/moc_cloudagent_vippool.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | 12 | message VipPoolRequest { 13 | repeated VipPool VipPools = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message VipPoolResponse { 18 | repeated VipPool VipPools = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message VipPoolPrecheckRequest { 24 | repeated VipPool VipPools = 1; 25 | } 26 | 27 | message VipPoolPrecheckResponse { 28 | // The precheck result: true if the precheck criteria is passed; otherwise, false 29 | google.protobuf.BoolValue Result = 1; 30 | 31 | // The error message if the precheck is not passed; otherwise, empty string 32 | string Error = 2; 33 | } 34 | 35 | message VipPool { 36 | string name = 1; 37 | string id = 2; 38 | string cidr = 3; 39 | string networkid = 4; 40 | string nodefqdn = 5; 41 | string groupName = 6; 42 | string locationName = 7; 43 | Status status = 8; 44 | string startip = 9 [(sensitive) = true]; 45 | string endip = 10 [(sensitive) = true]; 46 | Tags tags = 11; 47 | } 48 | 49 | service VipPoolAgent { 50 | rpc Invoke(VipPoolRequest) returns (VipPoolResponse) {} 51 | 52 | // Prechecks whether the system is able to create specified vip pools (but does not actually create them). 53 | rpc Precheck(VipPoolPrecheckRequest) returns (VipPoolPrecheckResponse) {} 54 | } 55 | 56 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/controlplane/moc_cloudagent_controlplane.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.controlplane; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message ControlPlaneRequest { 12 | repeated ControlPlane ControlPlanes = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message ControlPlaneResponse { 17 | repeated ControlPlane ControlPlanes = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | enum ControlPlaneState { 23 | NotLeader = 0; 24 | Leader = 1; 25 | } 26 | 27 | // There is a ControlPlane entity for every CloudAgent 28 | // participating to provide high availability without 29 | // FailoverCluster 30 | message ControlPlane { 31 | // id is an internal value required for all entities 32 | string id = 1; 33 | // name is an identifier provided during ControlPlane creation 34 | string name = 2; 35 | // locationName is the name of the Location entity this ControlPlane belongs to 36 | string locationName = 3; 37 | // fqdn is the fqdn, hostname, or ip address that this ControlPlane will use as part of the leadership election 38 | string fqdn = 4; 39 | // port is the port that this ControlPlane will use as part of the leadership election 40 | int32 port = 5; 41 | // status is a standard entity status 42 | Status status = 6; 43 | // state stores the last known election status of this ControlPlane 44 | ControlPlaneState state = 7; 45 | } 46 | 47 | service ControlPlaneAgent { 48 | rpc Invoke(ControlPlaneRequest) returns (ControlPlaneResponse) {} 49 | } 50 | 51 | -------------------------------------------------------------------------------- /rpc/cloudagent/storage/container/moc_cloudagent_container.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/storage"; 6 | package moc.cloudagent.storage; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_storageinfo.proto"; 11 | 12 | enum ContainerType { 13 | UNKNOWN = 0; 14 | SAN = 1; 15 | CSV = 2; 16 | SMB = 3; 17 | DAS = 4; 18 | } 19 | 20 | message ContainerRequest { 21 | repeated Container Containers = 1; 22 | Operation OperationType = 2; 23 | } 24 | 25 | message ContainerResponse { 26 | repeated Container Containers = 1; 27 | google.protobuf.BoolValue Result = 2; 28 | string Error = 3; 29 | } 30 | 31 | message ContainerPrecheckRequest { 32 | repeated Container Containers = 1; 33 | } 34 | 35 | message ContainerPrecheckResponse { 36 | // The precheck result: true if the precheck criteria is passed; otherwise, false 37 | google.protobuf.BoolValue Result = 1; 38 | 39 | // The error message if the precheck is not passed; otherwise, empty string 40 | string Error = 2; 41 | } 42 | 43 | message Container { 44 | string name = 1; 45 | string id = 2; 46 | string path = 4 [(sensitive) = true]; 47 | Status status = 5; 48 | string locationName = 6; 49 | StorageContainerInfo info = 7; 50 | Tags tags = 8; 51 | bool isolated = 9; 52 | } 53 | 54 | service ContainerAgent { 55 | rpc Invoke(ContainerRequest) returns (ContainerResponse) {} 56 | 57 | // Prechecks whether the system is able to create specified containers (but does not actually create them). 58 | rpc Precheck(ContainerPrecheckRequest) returns (ContainerPrecheckResponse) {} 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /pkg/logging/logger_test.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "github.com/stretchr/testify/assert" 7 | "os" 8 | "testing" 9 | 10 | "github.com/go-logr/logr/testr" 11 | ) 12 | 13 | func TestLogrLogger_Info(t *testing.T) { 14 | testLogr := testr.New(t) 15 | logrLogger := NewLogrLogger(testLogr) 16 | 17 | logrLogger.Info("test info message", "key1", "value1", "key2", 123) 18 | } 19 | 20 | func TestLogrLogger_Error(t *testing.T) { 21 | testLogr := testr.New(t) 22 | logrLogger := NewLogrLogger(testLogr) 23 | 24 | err := errors.New("test error") 25 | logrLogger.Error(err, "test error message", "key3", true, "key4", 456.78) 26 | } 27 | 28 | func TestDefaultLogger_Info(t *testing.T) { 29 | // Capture stdout 30 | oldStdout := os.Stdout 31 | r, w, _ := os.Pipe() 32 | os.Stdout = w 33 | 34 | logger := &DefaultLogger{} 35 | logger.Info("test info message", "key1", "value1", "key2", 123) 36 | 37 | w.Close() 38 | os.Stdout = oldStdout 39 | 40 | var buf bytes.Buffer 41 | buf.ReadFrom(r) 42 | output := buf.String() 43 | 44 | expectedOutput := "INFO: test info message key1 value1 key2 123\n" 45 | assert.Equal(t, expectedOutput, output) 46 | } 47 | 48 | func TestDefaultLogger_Error(t *testing.T) { 49 | // Capture stdout 50 | oldStdout := os.Stdout 51 | r, w, _ := os.Pipe() 52 | os.Stdout = w 53 | 54 | logger := &DefaultLogger{} 55 | err := errors.New("test error") 56 | logger.Error(err, "test error message", "key3", true, "key4", 456.78) 57 | 58 | w.Close() 59 | os.Stdout = oldStdout 60 | 61 | var buf bytes.Buffer 62 | buf.ReadFrom(r) 63 | output := buf.String() 64 | 65 | expectedOutput := "ERROR: test error message key3 true key4 456.78\nError: test error\n" 66 | assert.Equal(t, expectedOutput, output) 67 | } 68 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/certificate/moc_nodeagent_certificate.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | import "google/protobuf/wrappers.proto"; 8 | import "moc_common_common.proto"; 9 | 10 | enum CertificateType { 11 | Client = 0; 12 | Server = 1; 13 | IntermediateCA = 2; 14 | } 15 | 16 | message CertificateRequest { 17 | repeated Certificate Certificates = 1; 18 | } 19 | 20 | message CertificateResponse { 21 | repeated Certificate Certificates = 1; 22 | google.protobuf.BoolValue Result = 2; 23 | string Error = 3; 24 | } 25 | 26 | message Certificate { 27 | string name = 1; 28 | string id = 2; 29 | int64 notBefore = 3; 30 | int64 notAfter = 4; 31 | string certificate = 5 [(sensitive) = true]; 32 | Status status = 6; 33 | CertificateType type = 7; 34 | Entity entity = 8; 35 | Tags tags = 9; 36 | string thumbprint = 10; 37 | } 38 | 39 | message CSRRequest { 40 | repeated CertificateSigningRequest CSRs = 1; 41 | } 42 | 43 | message CertificateSigningRequest { 44 | string name = 1; 45 | string csr = 2 [(sensitive) = true]; 46 | string oldCertificate = 3 [(sensitive) = true]; 47 | Status status = 4; 48 | string caName = 5; 49 | int64 validity = 6; 50 | google.protobuf.BoolValue serverAuth = 7; 51 | } 52 | 53 | service CertificateAgent { 54 | rpc CreateOrUpdate(CertificateRequest) returns (CertificateResponse) {} 55 | rpc Get(CertificateRequest) returns (CertificateResponse) {} 56 | rpc Delete(CertificateRequest) returns (CertificateResponse) {} 57 | rpc Sign(CSRRequest) returns (CertificateResponse) {} 58 | rpc Renew(CSRRequest) returns (CertificateResponse) {} 59 | } 60 | -------------------------------------------------------------------------------- /rpc/nodeagent/compute/availabilityset/moc_nodeagent_availabilityset.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/compute"; 6 | package moc.nodeagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_computecommon.proto"; 11 | 12 | 13 | message AvailabilitySetRequest { 14 | repeated AvailabilitySet AvailabilitySets = 1; 15 | Operation OperationType = 2; 16 | } 17 | 18 | message AvailabilitySetResponse { 19 | repeated AvailabilitySet AvailabilitySets = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message VirtualMachineReference { 25 | string name = 1; 26 | } 27 | 28 | // avset structure is a flattened version of the model in the Azure sdk for go at 29 | // https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/resourcemanager/compute/armcompute/models.go 30 | message AvailabilitySet { 31 | string name = 1; 32 | string id = 2; 33 | Status status = 3; 34 | Tags tags = 4; 35 | Entity entity = 5; 36 | int32 platformFaultDomainCount = 6; 37 | repeated VirtualMachineReference virtualMachines = 7; 38 | } 39 | 40 | message AvailabilitySetOperationRequest { 41 | string AvailabilitySet = 1; 42 | string NodeagentVMName = 2; 43 | AvailabilitySetOperation OperationType = 3; 44 | } 45 | 46 | message AvailabilitySetOperationResponse { 47 | google.protobuf.BoolValue Result = 2; 48 | string Error = 3; 49 | } 50 | 51 | 52 | service AvailabilitySetAgent { 53 | rpc Invoke(AvailabilitySetRequest) returns (AvailabilitySetResponse) {} 54 | rpc Operate(AvailabilitySetOperationRequest) returns (AvailabilitySetOperationResponse) {} 55 | } -------------------------------------------------------------------------------- /gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Microsoft Corporation. 3 | # Licensed under the Apache v2.0 license. 4 | 5 | # Script that handles regenerating protobuf files. 6 | 7 | # Make sure the script exits on first failure and returns the 8 | # proper exit code to the shell. 9 | set -e 10 | 11 | while getopts "c" flag 12 | do 13 | case "${flag}" in 14 | c) checkGeneratedFiles=1;; 15 | esac 16 | done 17 | 18 | # Get script's directory. 19 | SCRIPT=$(readlink -f "$0") 20 | SCRIPTPATH=$(dirname "$SCRIPT") 21 | cd $SCRIPTPATH 22 | 23 | # Create directory for build files. 24 | mkdir -p ./bld/gen 25 | 26 | PROTOC_VER=3.11.4 27 | PROTOC_FILE=protoc-$PROTOC_VER-linux-x86_64.zip 28 | PROTOC_FILE_PATH=bld/$PROTOC_FILE 29 | 30 | # Check if protoc tool has already been downloaded. 31 | if [ ! -f $PROTOC_FILE_PATH ]; then 32 | # Download protoc tool. 33 | (cd bld && curl -OL https://github.com/google/protobuf/releases/download/v$PROTOC_VER/$PROTOC_FILE) 34 | fi 35 | 36 | # Unzip protoc tool. 37 | unzip -o $PROTOC_FILE_PATH -d bld/protoc 38 | 39 | GOPATH=$(go env GOPATH) 40 | 41 | ( 42 | export PATH=$GOPATH/bin:$SCRIPTPATH/bld/protoc/bin:$SCRIPTPATH/bld/protoc/include:$PATH 43 | 44 | # Generate the .go files from the .proto files. 45 | cd rpc 46 | /bin/bash ./gen_proto.sh 47 | ) 48 | 49 | # Copy generated .go files into repo. 50 | cp -rf ./bld/gen/github.com/microsoft/moc/rpc/* rpc/ 51 | 52 | # Cleanup. 53 | rm -rf ./bld/gen/ 54 | go mod tidy 55 | 56 | if [[ $checkGeneratedFiles ]]; then 57 | # Check if any files have changed. 58 | changed=$(git status --short) 59 | if [[ $changed ]]; then 60 | # Report warning. 61 | printf "\n\n##vso[task.logissue type=warning]Generated files are different:\n\n" 62 | 63 | # Log the diff. 64 | git --no-pager diff 65 | fi 66 | fi 67 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/role/moc_cloudagent_role.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_security.proto"; 11 | 12 | enum GeneralAccessOperation { 13 | Unspecified = 0; 14 | Read = 1; 15 | Write = 2; 16 | Delete = 3; 17 | All = 4; 18 | ProviderAction = 5; 19 | } 20 | 21 | enum AccessOperation { 22 | OBSOLETE_Read = 0 [deprecated=true]; 23 | OBSOLETE_Write = 1 [deprecated=true]; 24 | OBSOLETE_Delete = 2 [deprecated=true]; 25 | OBSOLETE_All = 3 [deprecated=true]; 26 | } 27 | 28 | message RoleRequest { 29 | repeated Role Roles = 1; 30 | Operation OperationType = 2; 31 | } 32 | 33 | message RoleResponse { 34 | repeated Role Roles = 1; 35 | google.protobuf.BoolValue Result = 2; 36 | string Error = 3; 37 | } 38 | 39 | message Action { 40 | AccessOperation operation = 1 [deprecated=true]; 41 | // ProviderType the rule works on 42 | ProviderType providerType = 2; 43 | // General access permissions 44 | GeneralAccessOperation generalOperation = 3; 45 | // Provider specific access permissions 46 | ProviderAccessOperation providerOperation = 4; 47 | } 48 | 49 | message Permission { 50 | repeated Action actions = 1; 51 | repeated Action notActions = 2; 52 | } 53 | 54 | message Role { 55 | string name = 1; 56 | string id = 2; 57 | // The scopes to which this role can be applied 58 | repeated Scope assignableScopes = 3; 59 | repeated Permission permissions = 4; 60 | Status status = 6; 61 | Tags tags = 7; 62 | } 63 | 64 | service RoleAgent { 65 | rpc Invoke(RoleRequest) returns (RoleResponse) {} 66 | } 67 | 68 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/virtualmachineimage/moc_cloudagent_virtualmachineimage.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message VirtualMachineImageRequest { 12 | repeated VirtualMachineImage VirtualMachineImages = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message VirtualMachineImageResponse { 17 | repeated VirtualMachineImage VirtualMachineImages = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message VirtualMachineImagePrecheckRequest { 23 | repeated VirtualMachineImage VirtualMachineImages = 1; 24 | } 25 | 26 | message VirtualMachineImagePrecheckResponse { 27 | // The precheck result: true if the precheck criteria is passed; otherwise, false 28 | google.protobuf.BoolValue Result = 1; 29 | 30 | // The error message if the precheck is not passed; otherwise, empty string 31 | string Error = 2; 32 | } 33 | 34 | message VirtualMachineImage { 35 | string name = 1; 36 | string id = 2; 37 | string imageReference = 3; 38 | string path = 4 [(sensitive) = true]; 39 | Status status = 5; 40 | string containerName = 6; 41 | string groupName = 18; 42 | string locationName = 19; 43 | Tags tags = 20; 44 | HyperVGeneration hyperVGeneration = 21; 45 | CloudInitDataSource cloudInitDataSource = 22; 46 | } 47 | 48 | service VirtualMachineImageAgent { 49 | rpc Invoke(VirtualMachineImageRequest) returns (VirtualMachineImageResponse) {} 50 | 51 | // Prechecks whether the system is able to create specified virtual machine images (but does not actually create them). 52 | rpc Precheck(VirtualMachineImagePrecheckRequest) returns (VirtualMachineImagePrecheckResponse) {} 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/virtualmachinescaleset/moc_cloudagent_virtualmachinescaleset.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_cloudagent_virtualmachine.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_cloudagent_networkinterface.proto"; 12 | 13 | message VirtualMachineScaleSetRequest { 14 | repeated VirtualMachineScaleSet VirtualMachineScaleSetSystems = 1; 15 | Operation OperationType = 2; 16 | } 17 | 18 | message VirtualMachineScaleSetResponse { 19 | repeated VirtualMachineScaleSet VirtualMachineScaleSetSystems = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message Sku { 25 | string name = 1; 26 | int64 capacity = 2; 27 | } 28 | 29 | message NetworkConfigurationScaleSet { 30 | repeated moc.cloudagent.network.NetworkInterface interfaces = 1; 31 | } 32 | 33 | message VirtualMachineProfile { 34 | string vmprefix = 1; 35 | NetworkConfigurationScaleSet network = 2; 36 | StorageConfiguration storage = 3; 37 | OperatingSystemConfiguration os = 4; 38 | HardwareConfiguration hardware = 5; 39 | SecurityConfiguration security = 6; 40 | } 41 | 42 | message VirtualMachineScaleSet { 43 | string name = 1; 44 | string id = 2; 45 | Sku sku = 3; 46 | VirtualMachineProfile virtualmachineprofile = 4; 47 | repeated VirtualMachine VirtualMachineSystems = 5; 48 | string nodefqdn = 6; 49 | string groupName = 7; 50 | string locationName = 8; 51 | Status status = 9; 52 | bool disableHighAvailability = 11; 53 | repeated string allowedOwnerNodes = 12; 54 | Tags tags = 13; 55 | } 56 | 57 | service VirtualMachineScaleSetAgent { 58 | rpc Invoke(VirtualMachineScaleSetRequest) returns (VirtualMachineScaleSetResponse) {} 59 | } 60 | 61 | -------------------------------------------------------------------------------- /rpc/nodeagent/compute/virtualmachinescaleset/moc_nodeagent_virtualmachinescaleset.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/compute"; 6 | package moc.nodeagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_nodeagent_virtualmachine.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_nodeagent_virtualnetworkinterface.proto"; 12 | 13 | message VirtualMachineScaleSetRequest { 14 | repeated VirtualMachineScaleSet VirtualMachineScaleSetSystems = 1; 15 | Operation OperationType = 2; 16 | } 17 | 18 | message VirtualMachineScaleSetResponse { 19 | repeated VirtualMachineScaleSet VirtualMachineScaleSetSystems = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message Sku { 25 | string name = 1; 26 | int64 capacity = 2; 27 | } 28 | 29 | message NetworkConfigurationScaleSet { 30 | repeated moc.nodeagent.network.VirtualNetworkInterface interfaces = 1; 31 | } 32 | 33 | message VirtualMachineProfile { 34 | string vmprefix = 1; 35 | NetworkConfigurationScaleSet network = 2; 36 | StorageConfiguration storage = 3; 37 | OperatingSystemConfiguration os = 4; 38 | HardwareConfiguration hardware = 5; 39 | SecurityConfiguration security = 6; 40 | } 41 | 42 | message VirtualMachineScaleSet { 43 | string name = 1; 44 | string id = 2; 45 | Sku sku = 3; 46 | VirtualMachineProfile virtualmachineprofile = 4; 47 | repeated VirtualMachine VirtualMachineSystems = 5; 48 | Status status = 7; 49 | bool DisableHighAvailability = 8; 50 | repeated string allowedOwnerNodes = 9; 51 | Entity entity = 10; 52 | HighAvailabilityState highAvailabilityState = 11; 53 | Tags tags = 12; 54 | } 55 | 56 | service VirtualMachineScaleSetAgent { 57 | rpc Invoke(VirtualMachineScaleSetRequest) returns (VirtualMachineScaleSetResponse) {} 58 | } 59 | 60 | -------------------------------------------------------------------------------- /pkg/logging/filetransfer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package logging 5 | 6 | import ( 7 | "context" 8 | "io" 9 | "os" 10 | ) 11 | 12 | const BUFFER_SIZE = 1024 13 | 14 | func UploadFile(ctx context.Context, filename string, sendFunc func([]byte, error) error) error { 15 | f, err := os.Open(filename) 16 | if err != nil { 17 | return err 18 | } 19 | defer f.Close() 20 | 21 | err = upload(ctx, f, sendFunc) 22 | if err != io.EOF { 23 | return err 24 | } 25 | return nil 26 | } 27 | 28 | func upload(ctx context.Context, reader io.Reader, sendFunc func([]byte, error) error) error { 29 | var err error 30 | for err == nil { 31 | buffer := make([]byte, BUFFER_SIZE) 32 | _, readErr := reader.Read(buffer) 33 | 34 | err = sendFunc(buffer, readErr) 35 | } 36 | return err 37 | } 38 | 39 | func Forward(ctx context.Context, sendFunc func([]byte, error) error, recFunc func() ([]byte, error)) error { 40 | var err error 41 | for err == nil { 42 | var buffer []byte 43 | buffer, readErr := recFunc() 44 | 45 | err = sendFunc(buffer, readErr) 46 | } 47 | return err 48 | } 49 | 50 | func ReceiveFile(ctx context.Context, filename string, recFunc func() ([]byte, error)) error { 51 | f, err := os.OpenFile(filename, os.O_CREATE, 0644) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | err = receive(ctx, f, recFunc) 57 | if err != io.EOF { 58 | // if hit an actual error then we want to clean up the file 59 | f.Close() 60 | os.Remove(filename) 61 | return err 62 | } 63 | defer f.Close() 64 | 65 | return nil 66 | } 67 | 68 | func receive(ctx context.Context, writer io.Writer, recFunc func() ([]byte, error)) error { 69 | var err error 70 | for err == nil { 71 | var buffer []byte 72 | buffer, err = recFunc() 73 | 74 | _, writeErr := writer.Write(buffer) 75 | if writeErr != nil { 76 | return writeErr 77 | } 78 | } 79 | return err 80 | } 81 | -------------------------------------------------------------------------------- /rpc/nodeagent/security/keyvault/key/moc_nodeagent_key.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/security"; 6 | package moc.nodeagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_security.proto"; 11 | import "google/protobuf/timestamp.proto"; 12 | 13 | 14 | message KeyRequest { 15 | repeated Key Keys = 1; 16 | Operation OperationType = 2; 17 | } 18 | 19 | message KeyResponse { 20 | repeated Key Keys = 1; 21 | google.protobuf.BoolValue Result = 2; 22 | string Error = 3; 23 | } 24 | 25 | message KeyOperationRequest { 26 | Key key = 1; 27 | string Data = 2 [(sensitive) = true]; 28 | Algorithm algorithm = 3; 29 | SignVerifyParams SignVerifyParams = 4; 30 | ProviderAccessOperation OperationType = 5; 31 | } 32 | 33 | message KeyOperationResponse { 34 | string Data = 1 [(sensitive) = true]; 35 | google.protobuf.BoolValue Result = 2; 36 | string Error = 3; 37 | Key key = 4; 38 | } 39 | 40 | message Key { 41 | string name = 1; 42 | string id = 2; 43 | string locationName = 3; 44 | // Public Key Value 45 | bytes publicKey = 4 [(sensitive) = true]; 46 | JsonWebKeyType type = 5; 47 | string vaultName = 6; 48 | Status status = 7; 49 | KeySize size = 8; 50 | JsonWebKeyCurveName curve = 9; 51 | repeated KeyOperation keyOps = 10; 52 | Tags tags = 11; 53 | Entity entity = 12; 54 | 55 | int64 keyRotationFrequencyInSeconds = 13; 56 | uint32 keyVersion = 14; 57 | google.protobuf.Timestamp creationTime = 15; 58 | 59 | // Private Key Value and wrapping information 60 | bytes privateKey = 16 [(sensitive) = true]; 61 | PrivateKeyWrappingInfo privateKeyWrappingInfo = 17; 62 | } 63 | 64 | service KeyAgent { 65 | rpc Invoke(KeyRequest) returns (KeyResponse) {} 66 | rpc Operate(KeyOperationRequest) returns (KeyOperationResponse) {} 67 | } 68 | -------------------------------------------------------------------------------- /rpc/nodeagent/network/virtualnetworkinterface/moc_nodeagent_virtualnetworkinterface.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/network"; 6 | package moc.nodeagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "google/protobuf/empty.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_notification.proto"; 12 | import "moc_common_networkcommon.proto"; 13 | 14 | message VirtualNetworkInterfaceRequest { 15 | repeated VirtualNetworkInterface VirtualNetworkInterfaces = 1; 16 | Operation OperationType = 2; 17 | } 18 | 19 | message VirtualNetworkInterfaceResponse { 20 | repeated VirtualNetworkInterface VirtualNetworkInterfaces = 1; 21 | google.protobuf.BoolValue Result = 2; 22 | string Error = 3; 23 | } 24 | 25 | enum NetworkType { 26 | VIRTUAL_NETWORK = 0; 27 | LOGICAL_NETWORK = 1; 28 | } 29 | 30 | message IpConfiguration { 31 | string ipaddress = 1 [(sensitive) = true]; 32 | string prefixlength = 2; 33 | string subnetid = 3; 34 | bool primary = 4; 35 | string gateway = 5 [(sensitive) = true]; 36 | IPAllocationMethod allocation = 6; 37 | NetworkType networkType = 7; 38 | } 39 | 40 | message VirtualNetworkInterface { 41 | string name = 1; 42 | string id = 2; 43 | enum NetworkInterfaceType { 44 | Local = 0; 45 | Remote = 1; 46 | } 47 | NetworkInterfaceType type = 3; 48 | repeated IpConfiguration ipconfigs = 4; 49 | string macaddress = 5 [(sensitive) = true]; 50 | Dns dnsSettings = 6 [(sensitive) = true]; 51 | string virtualMachineName = 7; 52 | Status status = 8; 53 | Entity entity = 9; 54 | uint32 iovWeight = 10; 55 | Tags tags = 11; 56 | } 57 | 58 | service VirtualNetworkInterfaceAgent { 59 | rpc Invoke(VirtualNetworkInterfaceRequest) returns (VirtualNetworkInterfaceResponse) {} 60 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 61 | } 62 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/placementgroup/moc_cloudagent_placementgroup.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_cloudagent_availabilityset.proto"; 11 | 12 | enum PlacementGroupType { 13 | Affinity = 0; 14 | AntiAffinity = 1; 15 | StrictAntiAffinity = 2; 16 | } 17 | 18 | enum PlacementGroupScope { 19 | Server = 0; 20 | Zone = 1 ; 21 | } 22 | 23 | message PlacementGroupRequest { 24 | repeated PlacementGroup PlacementGroups = 1; 25 | Operation OperationType = 2; 26 | } 27 | 28 | message PlacementGroupResponse { 29 | repeated PlacementGroup PlacementGroups = 1; 30 | google.protobuf.BoolValue Result = 2; 31 | string Error = 3; 32 | } 33 | 34 | message PlacementGroupPrecheckRequest { 35 | repeated PlacementGroup PlacementGroups = 1; 36 | } 37 | 38 | message PlacementGroupPrecheckResponse { 39 | // The precheck result: true if the precheck criteria is passed; otherwise, false 40 | google.protobuf.BoolValue Result = 1; 41 | 42 | // The error message if the precheck is not passed; otherwise, empty string 43 | string Error = 2; 44 | } 45 | 46 | message PlacementGroup { 47 | string name = 1; 48 | string id = 2; 49 | string locationName = 3; 50 | string groupName = 4; 51 | PlacementGroupType type = 5; 52 | PlacementGroupScope scope = 6; 53 | ZoneConfiguration zones = 7; 54 | Status status = 8; 55 | repeated VirtualMachineReference virtualMachines = 9; 56 | } 57 | 58 | service PlacementGroupAgent { 59 | rpc Invoke(PlacementGroupRequest) returns (PlacementGroupResponse) {} 60 | 61 | // Prechecks whether the system is able to create specified Placement Group (but does not actually create them). 62 | rpc Precheck(PlacementGroupPrecheckRequest) returns (PlacementGroupPrecheckResponse) {} 63 | } 64 | -------------------------------------------------------------------------------- /pkg/errors/codes/codes.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package codes 4 | 5 | import "strings" 6 | 7 | // MocCode - error codes used by MOC 8 | type MocCode uint32 9 | 10 | const ( 11 | OK MocCode = iota 12 | NotFound 13 | Degraded 14 | InvalidConfiguration 15 | InvalidInput 16 | InvalidType 17 | NotSupported 18 | AlreadyExists 19 | InUse 20 | Duplicates 21 | InvalidFilter 22 | Failed 23 | InvalidGroup 24 | InvalidVersion 25 | OldVersion 26 | OutOfCapacity 27 | OutOfNodeCapacity 28 | OutOfMemory 29 | UpdateFailed 30 | NotInitialized 31 | NotImplemented 32 | OutOfRange 33 | AlreadySet 34 | NotSet 35 | InconsistentState 36 | PendingState 37 | WrongHost 38 | PoolFull 39 | NoActionTaken 40 | Expired 41 | Revoked 42 | Timeout 43 | RunCommandFailed 44 | InvalidToken 45 | Unknown 46 | DeleteFailed 47 | DeletePending 48 | FileNotFound 49 | PathNotFound 50 | NotEnoughSpace 51 | AccessDenied 52 | BlobNotFound 53 | GenericFailure 54 | NoAuthenticationInformation 55 | MeasurementUnitError 56 | QuotaViolation 57 | IPOutOfRange 58 | VolumeNotFound 59 | VolumeDegraded 60 | VolumeAccessInconsistent 61 | PreCheckFailed 62 | ProviderNotReady 63 | DvdDriveNotFound 64 | // This is not a valid code, it is used to get the maximum code value. 65 | // Any new codes should be defined above this. 66 | _maxCode 67 | ) 68 | 69 | // IsValid - check if the code is a valid MocCode. 70 | func (c MocCode) IsValid() bool { 71 | if c >= _maxCode { 72 | return false 73 | } 74 | 75 | // Check if the string has been defined for the code. 76 | if strings.Contains(c.String(), "MocCode") { 77 | return false 78 | } 79 | 80 | return true 81 | } 82 | 83 | func (c MocCode) ToUint32() uint32 { 84 | return uint32(c) 85 | } 86 | 87 | // Convert an uint32 to a MocCode. If the uint32 is not a valid MocCode, return Unknown. 88 | func Convert(code uint32) MocCode { 89 | c := MocCode(code) 90 | if !c.IsValid() { 91 | return Unknown 92 | } 93 | return c 94 | } 95 | -------------------------------------------------------------------------------- /pkg/diagnostics/context.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package diagnostics 5 | 6 | import ( 7 | "context" 8 | 9 | "google.golang.org/grpc/metadata" 10 | ) 11 | 12 | type context_key int 13 | 14 | const CorrelationIdcontext_key context_key = 0 15 | const CorrelationIdMetadataKey string = "correlation-id-4b54b6c9-647a-4929-be87-481ba63fc04d" 16 | 17 | // Replace the context by using this method before making gRPC calls to MOC cloud/node agent, the 18 | // specified correlation-id will also be passed to server. 19 | func NewContextWithCorrelationId(parent context.Context, correlationId string) context.Context { 20 | ctx := parent 21 | if ctx == nil { 22 | ctx = context.Background() 23 | } 24 | 25 | // Adds to outgoing context 26 | md, ok := metadata.FromOutgoingContext(ctx) 27 | if ok { 28 | md.Set(CorrelationIdMetadataKey, correlationId) 29 | } else { 30 | md = metadata.Pairs(CorrelationIdMetadataKey, correlationId) 31 | } 32 | ctx = metadata.NewOutgoingContext(ctx, md) 33 | 34 | // Adds to runtime context 35 | return context.WithValue(ctx, CorrelationIdcontext_key, correlationId) 36 | } 37 | 38 | // For server-side MOC agent to pick the correlation-id which is previously set by gRPC client by 39 | // using the NewContextWithCorrelationId function 40 | func GetCorrelationIdFromIncomingContext(ctx context.Context) string { 41 | md, ok := metadata.FromIncomingContext(ctx) 42 | if ok { 43 | values := md.Get(CorrelationIdMetadataKey) 44 | if len(values) > 0 { 45 | return values[0] 46 | } 47 | } 48 | return "" 49 | } 50 | 51 | // Fetch the correlation-id from context, that was either previously set in the current call-stack 52 | // by using the NewContextWithCorrelationId function, or set by the client before making gPRC call. 53 | func GetCorrelationIdFromContext(ctx context.Context) string { 54 | value, ok := ctx.Value(CorrelationIdcontext_key).(string) 55 | if ok { 56 | return value 57 | } 58 | return GetCorrelationIdFromIncomingContext(ctx) 59 | } 60 | -------------------------------------------------------------------------------- /rpc/nodeagent/network/virtualnetwork/moc_nodeagent_virtualnetwork.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/network"; 6 | package moc.nodeagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "google/protobuf/empty.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_networkcommon.proto"; 12 | import "moc_common_notification.proto"; 13 | 14 | enum VirtualNetworkType { 15 | NAT = 0; 16 | Transparent = 1; 17 | L2Bridge = 2; 18 | L2Tunnel = 3; 19 | ICS = 4; 20 | Private = 5; 21 | Overlay = 6; 22 | Internal = 7; 23 | Mirrored = 8; 24 | } 25 | 26 | message VirtualNetworkRequest { 27 | repeated VirtualNetwork VirtualNetworks = 1; 28 | Operation OperationType = 2; 29 | } 30 | 31 | message VirtualNetworkResponse { 32 | repeated VirtualNetwork VirtualNetworks = 1; 33 | google.protobuf.BoolValue Result = 2; 34 | string Error = 3; 35 | } 36 | 37 | message VirtualNetwork { 38 | reserved 7; 39 | string name = 1; 40 | string id = 2; 41 | repeated Ipam ipams = 3; 42 | Dns dns = 4 [(sensitive) = true]; 43 | VirtualNetworkType type = 5; 44 | MacPool macPool = 6; 45 | Status status = 8; 46 | Entity entity = 9; 47 | Tags tags = 10; 48 | } 49 | 50 | message MacRange { 51 | string startMacAddress = 1 [(sensitive) = true]; 52 | string endMacAddress = 2 [(sensitive) = true]; 53 | } 54 | message MacPool { 55 | repeated MacRange ranges = 1; 56 | } 57 | 58 | message Subnet { 59 | string name = 1; 60 | string id = 2; 61 | string cidr = 3 [(sensitive) = true]; 62 | repeated Route routes = 4; 63 | IPAllocationMethod allocation = 5; 64 | uint32 vlan = 6; 65 | } 66 | message Ipam { 67 | string type = 1; 68 | repeated Subnet subnets = 2; 69 | } 70 | 71 | service VirtualNetworkAgent { 72 | rpc Invoke(VirtualNetworkRequest) returns (VirtualNetworkResponse) {} 73 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 74 | } 75 | 76 | -------------------------------------------------------------------------------- /pkg/tags/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation 2 | // Licensed under the Apache v2.0 license. 3 | package tags 4 | 5 | import ( 6 | "github.com/microsoft/moc/pkg/errors" 7 | common "github.com/microsoft/moc/rpc/common" 8 | ) 9 | 10 | // InitTag 11 | func InitTag(key, value string) *common.Tag { 12 | return &common.Tag{ 13 | Key: key, 14 | Value: value, 15 | } 16 | } 17 | 18 | // AddTag 19 | func AddTag(key, value string, tags *common.Tags) { 20 | tags.Tags = append(tags.GetTags(), InitTag(key, value)) 21 | } 22 | 23 | // DeleteTag 24 | func DeleteTag(key string, tags *common.Tags) { 25 | index := -1 26 | tagsList := tags.GetTags() 27 | for idx, tag := range tagsList { 28 | if tag.GetKey() == key { 29 | index = idx 30 | break 31 | } 32 | } 33 | 34 | if index != -1 { 35 | tags.Tags = append(tagsList[:index], tagsList[index+1:]...) 36 | } 37 | return 38 | } 39 | 40 | // GetTagValue 41 | func GetTagValue(key string, tags *common.Tags) (string, error) { 42 | for _, tag := range tags.GetTags() { 43 | if tag.GetKey() == key { 44 | return tag.GetValue(), nil 45 | } 46 | } 47 | return "", errors.Wrapf(errors.NotFound, "Missing tag %s", key) 48 | } 49 | 50 | // AddTagValue 51 | func AddTagValue(key, value string, tags *common.Tags) { 52 | for _, tag := range tags.GetTags() { 53 | if tag.GetKey() == key { 54 | tag.Value = value 55 | return 56 | } 57 | } 58 | tags.Tags = append(tags.GetTags(), InitTag(key, value)) 59 | return 60 | } 61 | 62 | // ProtoToMap 63 | func ProtoToMap(prototags *common.Tags) map[string]*string { 64 | tags := make(map[string]*string, len(prototags.GetTags())) 65 | for _, prototag := range prototags.GetTags() { 66 | tags[prototag.Key] = &prototag.Value 67 | } 68 | return tags 69 | } 70 | 71 | // MapToProto 72 | func MapToProto(tags map[string]*string) *common.Tags { 73 | prototags := common.Tags{} 74 | for key, value := range tags { 75 | tag := common.Tag{ 76 | Key: key, 77 | Value: *value, 78 | } 79 | prototags.Tags = append(prototags.GetTags(), &tag) 80 | } 81 | return &prototags 82 | } 83 | -------------------------------------------------------------------------------- /pkg/providerid/providerid.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package providerid 5 | 6 | import ( 7 | "strings" 8 | 9 | "github.com/microsoft/moc/pkg/errors" 10 | ) 11 | 12 | const ( 13 | ProviderName string = "moc" 14 | ProviderIDPrefix string = ProviderName + "://" 15 | ) 16 | 17 | type HostType string 18 | 19 | const ( 20 | HostTypeVM HostType = "vm" 21 | HostTypeBareMetal HostType = "baremetal" 22 | ) 23 | 24 | func FormatInstanceID(hostType HostType, machineName string) string { 25 | switch hostType { 26 | case HostTypeVM: 27 | // Don't append the host type for VMs to maintain consistency with previous versions. 28 | return machineName 29 | 30 | default: 31 | return string(hostType) + "/" + machineName 32 | } 33 | } 34 | 35 | func FormatProviderID(hostType HostType, machineName string) string { 36 | return ProviderIDPrefix + FormatInstanceID(hostType, machineName) 37 | } 38 | 39 | func ParseProviderID(providerID string) (HostType, string, error) { 40 | if providerID == "" { 41 | return "", "", errors.Wrap(errors.InvalidInput, "providerID is empty") 42 | } 43 | 44 | withoutPrefix := strings.TrimPrefix(providerID, ProviderIDPrefix) 45 | if withoutPrefix == providerID { 46 | return "", "", errors.Wrapf(errors.InvalidInput, "providerID is missing expected prefix (%s): %s", ProviderIDPrefix, providerID) 47 | } 48 | 49 | withoutPrefix = strings.TrimSpace(withoutPrefix) 50 | 51 | // Parse out the host type. 52 | split := strings.SplitN(withoutPrefix, "/", 2) 53 | if len(split) < 1 { 54 | return "", "", errors.Wrap(errors.InvalidInput, "providerID is invalid") 55 | } 56 | 57 | if len(split) == 1 { 58 | // VMs don't have the host type prefix. 59 | return HostTypeVM, split[0], nil 60 | } 61 | 62 | hostType := HostType(split[0]) 63 | machineName := split[1] 64 | 65 | if hostType != HostTypeBareMetal { 66 | return "", "", errors.Wrapf(errors.InvalidInput, "providerID contains unknown host type: %s", string(hostType)) 67 | } 68 | 69 | return hostType, machineName, nil 70 | } 71 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/baremetalhost/moc_cloudagent_baremetalhost.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_cloudagent_virtualmachine.proto"; 11 | 12 | enum BareMetalHostPowerState { 13 | Unknown = 0; 14 | Running = 1 ; 15 | Off = 2; 16 | } 17 | 18 | message BareMetalHostRequest { 19 | repeated BareMetalHost BareMetalHosts = 1; 20 | Operation OperationType = 2; 21 | } 22 | 23 | message BareMetalHostResponse { 24 | repeated BareMetalHost BareMetalHosts = 1; 25 | google.protobuf.BoolValue Result = 2; 26 | string Error = 3; 27 | } 28 | 29 | message BareMetalHostDisk { 30 | string diskName = 1; 31 | uint32 diskSizeGB = 2; 32 | } 33 | 34 | message BareMetalHostStorageConfiguration { 35 | repeated BareMetalHostDisk disks = 1; 36 | } 37 | 38 | message BareMetalHostNetworkInterface { 39 | string networkInterfaceName = 1; 40 | } 41 | 42 | message BareMetalHostNetworkConfiguration { 43 | repeated BareMetalHostNetworkInterface interfaces = 1; 44 | } 45 | 46 | message BareMetalHostSize { 47 | uint32 cpuCount = 1; 48 | uint32 gpuCount = 2; 49 | uint32 memoryMB = 3; 50 | } 51 | 52 | message BareMetalHostHardwareConfiguration { 53 | BareMetalHostSize machineSize = 1; 54 | } 55 | 56 | message BareMetalHost { 57 | string name = 1; 58 | string id = 2; 59 | BareMetalHostStorageConfiguration storage = 3; 60 | BareMetalHostNetworkConfiguration network = 4; 61 | BareMetalHostHardwareConfiguration hardware = 5; 62 | BareMetalHostPowerState powerState = 6; 63 | SecurityConfiguration security = 7; 64 | Status status = 8; 65 | string locationName = 9; 66 | string fqdn = 10; 67 | string certificate = 11; 68 | uint32 port = 12; 69 | uint32 authorizerPort = 13; 70 | Tags tags = 14; 71 | } 72 | 73 | service BareMetalHostAgent { 74 | rpc Invoke(BareMetalHostRequest) returns (BareMetalHostResponse) {} 75 | } 76 | -------------------------------------------------------------------------------- /rpc/cloudagent/compute/availabilityset/moc_cloudagent_availabilityset.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/compute"; 6 | package moc.cloudagent.compute; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message AvailabilitySetRequest { 12 | repeated AvailabilitySet AvailabilitySets = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message AvailabilitySetResponse { 17 | repeated AvailabilitySet AvailabilitySets = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message VirtualMachineReference { 23 | string groupName = 1; 24 | string name = 2; 25 | string realizedName = 3; // This is nodeagnet vm name 26 | } 27 | 28 | message AvailabilitySetPrecheckRequest { 29 | repeated AvailabilitySet AvailabilitySets = 1; 30 | } 31 | 32 | message AvailabilitySetPrecheckResponse { 33 | // The precheck result: true if the precheck criteria is passed; otherwise, false 34 | google.protobuf.BoolValue Result = 1; 35 | 36 | // The error message if the precheck is not passed; otherwise, empty string 37 | string Error = 2; 38 | } 39 | 40 | // avset structure is a flattened version of the model in the Azure sdk for go at 41 | // https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/resourcemanager/compute/armcompute/models.go 42 | message AvailabilitySet { 43 | string name = 1; 44 | string id = 2; 45 | string locationName = 3; 46 | string groupName = 4; 47 | Status status = 5; 48 | Tags tags = 6; 49 | int32 platformFaultDomainCount = 7; 50 | repeated VirtualMachineReference virtualMachines = 8; 51 | } 52 | 53 | service AvailabilitySetAgent { 54 | rpc Invoke(AvailabilitySetRequest) returns (AvailabilitySetResponse) {} 55 | 56 | // Prechecks whether the system is able to create specified availability set (but does not actually create them). 57 | rpc Precheck(AvailabilitySetPrecheckRequest) returns (AvailabilitySetPrecheckResponse) {} 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /pkg/logging/loggingRedirect.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | // Package loggingRedirect - Creates a log file the redirects STD output. 5 | package logging 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "path/filepath" 11 | 12 | path "github.com/microsoft/moc/pkg/path" 13 | ) 14 | 15 | var ( 16 | oldStdOut *os.File 17 | oldStdErr *os.File 18 | logFile *os.File 19 | ) 20 | 21 | func createLogFile(logFileAbsolutePath string, logFileName string) (*os.File, error) { 22 | // Create log path 23 | os.MkdirAll(logFileAbsolutePath, os.ModeDir) //nolint:golint,errcheck 24 | 25 | err := path.CheckPath(logFileAbsolutePath) 26 | if err != nil { 27 | return nil, err 28 | } 29 | path := filepath.Join(logFileAbsolutePath, logFileName) 30 | logFile, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | st, err := logFile.Stat() 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | // If there are contents in the file already, move the file and replace it. 41 | if st.Size() > 0 { 42 | logFile.Close() 43 | os.Rename(path, path+".old") //nolint:golint,errcheck 44 | logFile, err = os.Create(path) 45 | if err != nil { 46 | return nil, err 47 | } 48 | } 49 | 50 | return logFile, nil 51 | } 52 | 53 | // StartRedirectingOutput 54 | func StartRedirectingOutput(logFileAbsolutePath string, logFileName string) error { 55 | // Save previous values 56 | oldStdOut = os.Stdout 57 | oldStdErr = os.Stderr 58 | 59 | // Create output file 60 | var err error 61 | logFile, err = createLogFile(logFileAbsolutePath, logFileName) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | RedirectStdErr(logFile) 67 | // Set output to file 68 | os.Stdout = logFile 69 | log.SetOutput(logFile) 70 | 71 | return nil 72 | } 73 | 74 | // RestoreOutput 75 | func RestoreOutput() { 76 | // Restoring previous values 77 | os.Stdout = oldStdOut 78 | os.Stderr = oldStdErr 79 | log.SetOutput(os.Stderr) 80 | 81 | if logFile != nil { 82 | // Close log file 83 | logFile.Close() 84 | logFile = nil 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /pkg/certs/cert_utils.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package certs 5 | 6 | import ( 7 | "fmt" 8 | "time" 9 | 10 | "github.com/microsoft/moc/pkg/errors" 11 | ) 12 | 13 | const ( 14 | // formatSHA256 is the prefix for pins that are full-length SHA-256 hashes encoded in base 16 (hex) 15 | formatSHA256 = "sha256" 16 | ) 17 | 18 | type backOffFactor struct { 19 | renewBackoffFactor float64 20 | errorBackoffFactor float64 21 | } 22 | 23 | type backOffDuration struct { 24 | RenewBackoffDuration time.Duration 25 | ErrorBackoffDuration time.Duration 26 | } 27 | 28 | func NewBackOffFactor(renewBackoffFactor, errorBackoffFactor float64) (factor *backOffFactor, err error) { 29 | if renewBackoffFactor <= 0 { 30 | return nil, errors.Wrapf(errors.InvalidInput, "Factor renewBackoffFactor(%f) cannot be <= 0.0", renewBackoffFactor) 31 | } 32 | if errorBackoffFactor <= 0 { 33 | return nil, errors.Wrapf(errors.InvalidInput, "Factor errorBackoffFactor(%f) cannot be <= 0.0", errorBackoffFactor) 34 | } 35 | return &backOffFactor{renewBackoffFactor: renewBackoffFactor, errorBackoffFactor: errorBackoffFactor}, nil 36 | } 37 | 38 | func calculateTime(before, after, now time.Time, factor *backOffFactor) (duration *backOffDuration) { 39 | validity := after.Sub(before) 40 | 41 | errorBackoff := time.Duration(float64(validity.Nanoseconds()) * factor.errorBackoffFactor) 42 | 43 | tresh := time.Duration(float64(validity.Nanoseconds()) * factor.renewBackoffFactor) 44 | 45 | treshNotAfter := after.Add(-tresh) 46 | return &backOffDuration{RenewBackoffDuration: treshNotAfter.Sub(now), ErrorBackoffDuration: errorBackoff} 47 | } 48 | 49 | func CalculateRenewTime(certificate string, factor *backOffFactor) (duration *backOffDuration, err error) { 50 | 51 | x509Cert, err := DecodeCertPEM([]byte(certificate)) 52 | if err != nil { 53 | return 54 | } 55 | fmt.Println("factor", factor) 56 | return calculateTime(x509Cert.NotBefore, x509Cert.NotAfter, time.Now(), factor), nil 57 | } 58 | 59 | func IsCertificateExpired(certificate string) (bool, error) { 60 | x509Cert, err := DecodeCertPEM([]byte(certificate)) 61 | if err != nil { 62 | return false, err 63 | } 64 | return x509Cert.NotAfter.Before(time.Now()), nil 65 | } 66 | -------------------------------------------------------------------------------- /rpc/cloudagent/network/publicipaddress/moc_cloudagent_publicipaddress.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_networkcommon.proto"; 11 | 12 | // --------------------------------------------------------------------------------------------------- 13 | // Azure public IP address overview 14 | // https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/virtual-network-public-ip-address 15 | // Azure CLI: 16 | // https://learn.microsoft.com/en-us/cli/azure/network/public-ip?view=azure-cli-latest 17 | // --------------------------------------------------------------------------------------------------- 18 | 19 | message PublicIPAddressRequest { 20 | repeated PublicIPAddress PublicIPAddresses = 1; 21 | Operation OperationType = 2; 22 | } 23 | 24 | message PublicIPAddressResponse { 25 | repeated PublicIPAddress PublicIPAddresses = 1; 26 | google.protobuf.BoolValue Result = 2; 27 | string Error = 3; 28 | } 29 | 30 | message PublicIPAddressPrecheckRequest { 31 | repeated PublicIPAddress PublicIPAddresses = 1; 32 | } 33 | 34 | message PublicIPAddressPrecheckResponse { 35 | // The precheck result: true if the precheck criteria is passed; otherwise, false 36 | google.protobuf.BoolValue Result = 1; 37 | 38 | // The error message if the precheck is not passed; otherwise, empty string 39 | string Error = 2; 40 | } 41 | 42 | message PublicIPAddress { 43 | string name = 1; 44 | string id = 2; 45 | string ipAddress = 3 [(sensitive) = true]; 46 | IPAllocationMethod allocation = 4; 47 | IPVersion ipVersion = 5; 48 | int32 idleTimeoutInMinutes = 6; 49 | string groupName = 7; 50 | string locationName = 8; 51 | Status status = 9; 52 | Tags tags = 10; 53 | } 54 | 55 | service PublicIPAddressAgent { 56 | rpc Invoke(PublicIPAddressRequest) returns (PublicIPAddressResponse) {} 57 | 58 | // Prechecks whether the system is able to create specified public IP address (but does not actually create them). 59 | rpc Precheck(PublicIPAddressPrecheckRequest) returns (PublicIPAddressPrecheckResponse) {} 60 | } 61 | -------------------------------------------------------------------------------- /rpc/cloudagent/network/logicalnetwork/moc_cloudagent_logicalnetwork.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_networkcommon.proto"; 11 | 12 | message LogicalNetworkRequest { 13 | repeated LogicalNetwork LogicalNetworks = 1; 14 | Operation OperationType = 2; 15 | } 16 | 17 | message LogicalNetworkResponse { 18 | repeated LogicalNetwork LogicalNetworks = 1; 19 | google.protobuf.BoolValue Result = 2; 20 | string Error = 3; 21 | } 22 | 23 | message LogicalNetworkPrecheckRequest { 24 | repeated LogicalNetwork LogicalNetworks = 1; 25 | } 26 | 27 | message LogicalNetworkPrecheckResponse { 28 | // The precheck result: true if the precheck criteria is passed; otherwise, false 29 | google.protobuf.BoolValue Result = 1; 30 | 31 | // The error message if the precheck is not passed; otherwise, empty string 32 | string Error = 2; 33 | } 34 | 35 | message LogicalNetwork { 36 | string name = 1; 37 | string id = 2; 38 | repeated LogicalSubnet subnets = 3; 39 | bool networkVirtualizationEnabled = 4; 40 | Status status = 5; 41 | string locationName = 6; 42 | string macPoolName = 7 [(sensitive) = true]; 43 | Tags tags = 8; 44 | repeated AdvancedNetworkPolicy advancedPolicies = 9; 45 | } 46 | 47 | message LogicalSubnet { 48 | string name = 1; 49 | string id = 2; 50 | string addressPrefix = 3; 51 | repeated Route routes = 4; 52 | IPAllocationMethod allocation = 5; 53 | uint32 vlan = 6; 54 | repeated IPPool ipPools = 7; 55 | Dns dns = 8 [(sensitive) = true]; 56 | bool isPublic = 9; // Indicates IPPools from this subnet can be used to allocate public IP address by SDN. 57 | Tags tags = 10; 58 | NetworkSecurityGroupReference networkSecurityGroupRef = 11; 59 | } 60 | 61 | service LogicalNetworkAgent { 62 | rpc Invoke(LogicalNetworkRequest) returns (LogicalNetworkResponse) {} 63 | 64 | // Prechecks whether the system is able to create specified logical networks (but does not actually create them). 65 | rpc Precheck(LogicalNetworkPrecheckRequest) returns (LogicalNetworkPrecheckResponse) {} 66 | } 67 | 68 | -------------------------------------------------------------------------------- /pkg/validations/proxy_validation.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package validations 5 | 6 | import ( 7 | "crypto/tls" 8 | "crypto/x509" 9 | "fmt" 10 | "net/http" 11 | "net/url" 12 | 13 | "github.com/microsoft/moc/pkg/errors" 14 | commonproto "github.com/microsoft/moc/rpc/common" 15 | ) 16 | 17 | func ValidateProxyURL(proxyURL string) (*url.URL, error) { 18 | parsedURL, err := url.ParseRequestURI(proxyURL) 19 | 20 | if err != nil { 21 | return nil, errors.Wrapf(errors.InvalidInput, "%s", err.Error()) 22 | } 23 | 24 | // Check if url scheme is http or https 25 | if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" { 26 | return nil, errors.Wrapf(errors.InvalidInput, "Invalid proxy URL. The URL scheme should be http or https") 27 | } 28 | 29 | return parsedURL, nil 30 | } 31 | 32 | func TestProxyUrlConnection(parsedURL *url.URL, certContent string, getRequestUrl string) error { 33 | // Create a certificate pool 34 | caCertPool := x509.NewCertPool() 35 | caCertPool.AppendCertsFromPEM([]byte(certContent)) 36 | 37 | // Create a transport 38 | transport := &http.Transport{ 39 | Proxy: http.ProxyURL(parsedURL), 40 | TLSClientConfig: &tls.Config{ 41 | RootCAs: caCertPool, 42 | }, 43 | } 44 | 45 | // Create a client 46 | client := &http.Client{ 47 | Transport: transport, 48 | } 49 | 50 | if getRequestUrl == "" { 51 | getRequestUrl = "https://mcr.microsoft.com" 52 | } 53 | 54 | // Test the HTTP GET request 55 | response, err := client.Get(getRequestUrl) 56 | if err != nil { 57 | return errors.Wrapf(errors.InvalidInput, "%s", err.Error()) 58 | } else { 59 | defer response.Body.Close() 60 | fmt.Println("Connected successfully to the proxy server") 61 | } 62 | 63 | return nil 64 | } 65 | 66 | func ValidateProxyParameters(proxyConfig *commonproto.ProxyConfiguration) error { 67 | if proxyConfig == nil { 68 | return nil 69 | } 70 | // Validations for proxy parameters 71 | if len(proxyConfig.HttpProxy) > 0 { 72 | _, err := ValidateProxyURL(proxyConfig.HttpProxy) 73 | if err != nil { 74 | return err 75 | } 76 | } 77 | 78 | if len(proxyConfig.HttpsProxy) > 0 { 79 | _, err := ValidateProxyURL(proxyConfig.HttpsProxy) 80 | if err != nil { 81 | return err 82 | } 83 | } 84 | 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/keyvault/key/moc_cloudagent_key.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "google/protobuf/duration.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_security.proto"; 12 | 13 | 14 | message KeyRequest { 15 | repeated Key Keys = 1; 16 | Operation OperationType = 2; 17 | } 18 | 19 | message KeyResponse { 20 | repeated Key Keys = 1; 21 | google.protobuf.BoolValue Result = 2; 22 | string Error = 3; 23 | } 24 | 25 | message KeyOperationRequest { 26 | Key key = 1; 27 | string Data = 2 [(sensitive) = true]; 28 | Algorithm algorithm = 3; 29 | KeyOperation OBSOLETE_OperationType = 4 [deprecated=true]; 30 | SignVerifyParams SignVerifyParams = 5; 31 | ProviderAccessOperation OperationType = 6; 32 | } 33 | 34 | message KeyOperationResponse { 35 | string Data = 1 [(sensitive) = true]; 36 | google.protobuf.BoolValue Result = 2; 37 | string Error = 3; 38 | string keyVersion = 4; 39 | } 40 | 41 | message PrivateKeyWrappingInfo { 42 | string WrappingKeyName = 1; 43 | bytes WrappingKeyPublic = 2 [(sensitive) = true]; 44 | KeyWrappingAlgorithm WrappingAlgorithm = 3; 45 | } 46 | 47 | message SignVerifyParams { 48 | JSONWebKeySignatureAlgorithm algorithm = 1; 49 | string signature = 2 [(sensitive) = true]; 50 | } 51 | 52 | message Key { 53 | string name = 1; 54 | string id = 2; 55 | string locationName = 3; 56 | // Public Key Value 57 | bytes publicKey = 4 [(sensitive) = true]; 58 | JsonWebKeyType type = 5; 59 | string vaultName = 6; 60 | string groupName = 7; 61 | Status status = 8; 62 | KeySize size = 9; 63 | JsonWebKeyCurveName curve = 10; 64 | repeated KeyOperation keyOps = 11; 65 | Tags tags = 12; 66 | int64 keyRotationFrequencyInSeconds = 13; 67 | // Private Key Value and wrapping information 68 | bytes privateKey = 14 [(sensitive) = true]; 69 | PrivateKeyWrappingInfo privateKeyWrappingInfo = 15; 70 | string keyVersion = 16; 71 | google.protobuf.Duration keyAge = 17; 72 | } 73 | 74 | service KeyAgent { 75 | rpc Invoke(KeyRequest) returns (KeyResponse) {} 76 | rpc Operate(KeyOperationRequest) returns (KeyOperationResponse) {} 77 | } 78 | -------------------------------------------------------------------------------- /rpc/common/moc_common_security.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/common"; 6 | 7 | package moc; 8 | 9 | import "moc_common_common.proto"; 10 | 11 | enum Algorithm { 12 | A_UNKNOWN = 0; 13 | RSA15 = 1; 14 | RSAOAEP = 2; 15 | RSAOAEP256 = 3; 16 | A256KW = 4; 17 | A256CBC = 5; 18 | } 19 | 20 | enum JSONWebKeySignatureAlgorithm { 21 | RSNULL = 0; 22 | ES256 = 1; 23 | ES256K = 2; 24 | ES384 = 3; 25 | ES512 = 4; 26 | PS256 = 5; 27 | PS384 = 6; 28 | PS512 = 7; 29 | RS256 = 8; 30 | RS384 = 9; 31 | RS512 = 10; 32 | } 33 | 34 | enum KeyOperation { 35 | ENCRYPT = 0 [deprecated=true]; 36 | DECRYPT = 1 [deprecated=true]; 37 | WRAPKEY = 2 [deprecated=true]; 38 | UNWRAPKEY = 3 [deprecated=true]; 39 | SIGN = 4 [deprecated=true]; 40 | VERIFY = 5 [deprecated=true]; 41 | } 42 | 43 | // https://docs.microsoft.com/en-us/rest/api/keyvault/createkey/createkey#jsonwebkeytype 44 | enum JsonWebKeyType { 45 | EC = 0; 46 | EC_HSM = 1; 47 | RSA = 2; 48 | RSA_HSM = 3; 49 | OCT = 4; 50 | AES = 5; 51 | } 52 | 53 | enum JsonWebKeyCurveName { 54 | P_256 = 0; 55 | P_256K = 1; 56 | P_384 = 2; 57 | P_521 = 3; 58 | } 59 | 60 | enum KeySize { 61 | K_UNKNOWN = 0; 62 | _256 = 1; 63 | _2048 = 2; 64 | _3072 = 3; 65 | _4096 = 4; 66 | } 67 | 68 | enum IdentityOperation { 69 | REVOKE = 0 [deprecated=true]; 70 | ROTATE = 1 [deprecated=true]; 71 | } 72 | 73 | enum IdentityCertificateOperation { 74 | CREATE_CERTIFICATE = 0 [deprecated=true]; 75 | RENEW_CERTIFICATE = 1 [deprecated=true]; 76 | } 77 | 78 | enum KeyWrappingAlgorithm { 79 | CKM_RSA_AES_KEY_WRAP = 0; 80 | RSA_AES_KEY_WRAP_256 = 1; 81 | RSA_AES_KEY_WRAP_384 = 2; 82 | NO_KEY_WRAP = 3; 83 | } 84 | 85 | message Scope { 86 | string location = 1; 87 | string resourceGroup = 2; 88 | ProviderType providerType = 3; 89 | string resource = 4; 90 | } 91 | 92 | message PrivateKeyWrappingInfo { 93 | string WrappingKeyName = 1; 94 | bytes WrappingKeyPublic = 2 [(sensitive) = true]; 95 | KeyWrappingAlgorithm WrappingAlgorithm = 3; 96 | } 97 | 98 | message SignVerifyParams { 99 | JSONWebKeySignatureAlgorithm algorithm = 1; 100 | string signature = 2 [(sensitive) = true]; 101 | } -------------------------------------------------------------------------------- /rpc/cloudagent/network/networksecuritygroup/moc_cloudagent_networksecuritygroup.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_networkcommon.proto"; 11 | 12 | enum Action { 13 | Allow = 0; 14 | Deny = 1; 15 | } 16 | 17 | enum Direction { 18 | Inbound = 0; 19 | Outbound = 1; 20 | } 21 | 22 | message NetworkSecurityGroupRequest { 23 | repeated NetworkSecurityGroup NetworkSecurityGroups = 1; 24 | Operation OperationType = 2; 25 | } 26 | 27 | message NetworkSecurityGroupResponse { 28 | repeated NetworkSecurityGroup NetworkSecurityGroups = 1; 29 | google.protobuf.BoolValue Result = 2; 30 | string Error = 3; 31 | } 32 | 33 | message NetworkSecurityGroupPrecheckRequest { 34 | repeated NetworkSecurityGroup NetworkSecurityGroups = 1; 35 | } 36 | 37 | message NetworkSecurityGroupPrecheckResponse { 38 | // The precheck result: true if the precheck criteria is passed; otherwise, false 39 | google.protobuf.BoolValue Result = 1; 40 | 41 | // The error message if the precheck is not passed; otherwise, empty string 42 | string Error = 2; 43 | } 44 | 45 | message NetworkSecurityGroupRule { 46 | string name = 1; 47 | string description = 2; 48 | Action action = 3; 49 | Direction direction = 4; 50 | string sourceAddressPrefix = 5; 51 | string destinationAddressPrefix = 6; 52 | string sourcePortRange = 7; 53 | string destinationPortRange = 8; 54 | Protocol protocol = 9; 55 | uint32 priority = 10; 56 | bool logging = 11; 57 | bool isDefaultRule = 12; 58 | } 59 | 60 | message NetworkSecurityGroup { 61 | reserved 5; // deprecated group name (now parented to location) 62 | string name = 1; 63 | string id = 2; 64 | repeated NetworkSecurityGroupRule networksecuritygrouprules = 3; 65 | string locationName = 6; 66 | Status status = 7; 67 | Tags tags = 8; 68 | } 69 | 70 | service NetworkSecurityGroupAgent { 71 | rpc Invoke(NetworkSecurityGroupRequest) returns (NetworkSecurityGroupResponse) {} 72 | 73 | // Prechecks whether the system is able to create specified network security groups (but does not actually create them). 74 | rpc Precheck(NetworkSecurityGroupPrecheckRequest) returns (NetworkSecurityGroupPrecheckResponse) {} 75 | } 76 | -------------------------------------------------------------------------------- /pkg/auth/mock/auth_mock.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/microsoft/moc/pkg/auth (interfaces: Authorizer) 3 | 4 | // Package mock_auth is a generated GoMock package. 5 | package mock_auth 6 | 7 | import ( 8 | reflect "reflect" 9 | 10 | gomock "github.com/golang/mock/gomock" 11 | credentials "google.golang.org/grpc/credentials" 12 | ) 13 | 14 | // MockAuthorizer is a mock of Authorizer interface. 15 | type MockAuthorizer struct { 16 | ctrl *gomock.Controller 17 | recorder *MockAuthorizerMockRecorder 18 | } 19 | 20 | // MockAuthorizerMockRecorder is the mock recorder for MockAuthorizer. 21 | type MockAuthorizerMockRecorder struct { 22 | mock *MockAuthorizer 23 | } 24 | 25 | // NewMockAuthorizer creates a new mock instance. 26 | func NewMockAuthorizer(ctrl *gomock.Controller) *MockAuthorizer { 27 | mock := &MockAuthorizer{ctrl: ctrl} 28 | mock.recorder = &MockAuthorizerMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use. 33 | func (m *MockAuthorizer) EXPECT() *MockAuthorizerMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // WithRPCAuthorization mocks base method. 38 | func (m *MockAuthorizer) WithRPCAuthorization() credentials.PerRPCCredentials { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "WithRPCAuthorization") 41 | ret0, _ := ret[0].(credentials.PerRPCCredentials) 42 | return ret0 43 | } 44 | 45 | // WithRPCAuthorization indicates an expected call of WithRPCAuthorization. 46 | func (mr *MockAuthorizerMockRecorder) WithRPCAuthorization() *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithRPCAuthorization", reflect.TypeOf((*MockAuthorizer)(nil).WithRPCAuthorization)) 49 | } 50 | 51 | // WithTransportAuthorization mocks base method. 52 | func (m *MockAuthorizer) WithTransportAuthorization() credentials.TransportCredentials { 53 | m.ctrl.T.Helper() 54 | ret := m.ctrl.Call(m, "WithTransportAuthorization") 55 | ret0, _ := ret[0].(credentials.TransportCredentials) 56 | return ret0 57 | } 58 | 59 | // WithTransportAuthorization indicates an expected call of WithTransportAuthorization. 60 | func (mr *MockAuthorizerMockRecorder) WithTransportAuthorization() *gomock.Call { 61 | mr.mock.ctrl.T.Helper() 62 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithTransportAuthorization", reflect.TypeOf((*MockAuthorizer)(nil).WithTransportAuthorization)) 63 | } 64 | -------------------------------------------------------------------------------- /.pipelines/build.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Build 3 | 4 | pool: 5 | vmImage: 'ubuntu-latest' 6 | 7 | variables: 8 | - group: moc-build 9 | - name: GO111MODULE 10 | value: 'on' 11 | - name: GDN_VERSION 12 | value: '0.110.0-linux' 13 | - name: GDNP_VERSION 14 | value: '1.61.0-linux' 15 | - name: LGTM.UploadSnapshot 16 | value: true 17 | 18 | steps: 19 | - task: GoTool@0 20 | inputs: 21 | version: '1.24.3' 22 | - task: InstallSSHKey@0 23 | inputs: 24 | knownHostsEntry: '$(KNOWN_HOST)' 25 | sshPublicKey: '$(SSH_PUBLIC_KEY)' 26 | sshKeySecureFile: 'azure-pipelines-ssh-key-new' 27 | - script: | 28 | git config --global url.ssh://git@github.com/.insteadOf https://github.com/ 29 | displayName: 'Set up the Go workspace' 30 | 31 | - script: | 32 | make pipeline 33 | displayName: 'Generate Protobuf' 34 | 35 | - script: | 36 | # Static binary workaround for CodeQL and Go 1.21 and higher 37 | # https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/codeql/troubleshooting/onboarding/language-compiled 38 | mkdir $AGENT_TEMPDIRECTORY/codeql-go-tracing 39 | WORKAROUND_DIR=$AGENT_TEMPDIRECTORY/codeql-go-tracing 40 | WHICH_GO=$(which go) 41 | cat > "${WORKAROUND_DIR}/go" <") { 54 | err = errors.Wrapf(errors.InvalidInput, "Path [%s] contains invalid operators like '&', '|', ';', '^', '>'", path) 55 | return err 56 | } 57 | 58 | // Step 1: Remove inhereted permissions 59 | cmd := exec.Command("icacls", path, "/inheritance:r") 60 | _, err = cmd.CombinedOutput() 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Step 2: Grant admin permission to the directory 66 | getBuiltInAdminGroupName := `function Get-BuiltInAdminName { 67 | param() 68 | $obj = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") 69 | $name = ($obj.Translate([System.Security.Principal.NTAccount])).Value 70 | "$name" 71 | } 72 | ` 73 | builtInAdminGroupName, err := mocExecutePowershell(getBuiltInAdminGroupName, `Get-BuiltInAdminName`) 74 | if err != nil { 75 | return err 76 | } 77 | builtInAdminGroupNamePermissions := strings.TrimSpace(builtInAdminGroupName) + ":(OI)(CI)(F)" 78 | 79 | cmd = exec.Command("icacls", path, "/grant", builtInAdminGroupNamePermissions) 80 | _, err = cmd.CombinedOutput() 81 | if err != nil { 82 | return err 83 | } 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /rpc/cloudagent/security/identity/moc_cloudagent_identity.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/security"; 6 | package moc.cloudagent.security; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_cloudagent_certificate.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_security.proto"; 12 | 13 | message IdentityRequest { 14 | repeated Identity Identitys = 1; 15 | Operation OperationType = 2; 16 | } 17 | 18 | message IdentityResponse { 19 | repeated Identity Identitys = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message IdentityOperationRequest { 25 | repeated Identity Identities = 1; 26 | IdentityOperation OBSOLETE_OperationType = 2 [deprecated=true]; 27 | ProviderAccessOperation OperationType = 3; 28 | } 29 | 30 | message IdentityCertificateRequest { 31 | string IdentityName = 1; 32 | repeated CertificateSigningRequest CSR = 2; 33 | IdentityCertificateOperation OBSOLETE_OperationType = 3 [deprecated=true]; 34 | ProviderAccessOperation OperationType = 4; 35 | } 36 | 37 | message IdentityCertificateResponse { 38 | repeated Certificate Certificates = 1; 39 | google.protobuf.BoolValue Result = 2; 40 | string Error = 3; 41 | } 42 | 43 | message IdentityPrecheckRequest { 44 | repeated Identity Identities = 1; 45 | } 46 | 47 | message IdentityPrecheckResponse { 48 | // The precheck result: true if the precheck criteria is passed; otherwise, false 49 | google.protobuf.BoolValue Result = 1; 50 | 51 | // The error message if the precheck is not passed; otherwise, empty string 52 | string Error = 2; 53 | } 54 | 55 | message Identity { 56 | string name = 1; 57 | string id = 2; 58 | string resourceGroup = 3; 59 | string password = 4 [(sensitive) = true]; 60 | string token = 5 [(sensitive) = true]; 61 | Status status = 7; 62 | string locationName = 10; 63 | Tags tags = 11; 64 | map certificates = 12 [(sensitive) = true]; 65 | int64 tokenExpiry = 13 [deprecated = true]; 66 | ClientType clientType = 14; 67 | string cloudFqdn = 15; 68 | int32 cloudPort = 16; 69 | int32 cloudAuthPort = 17; 70 | AuthenticationType authType = 18 [deprecated = true];; 71 | bool revoked = 19; 72 | bool autoRotate = 20; 73 | string loginFilePath = 21; 74 | int64 tokenExpiryInSeconds = 22; 75 | } 76 | 77 | service IdentityAgent { 78 | rpc Invoke(IdentityRequest) returns (IdentityResponse) {} 79 | rpc Operate(IdentityOperationRequest) returns (IdentityResponse) {} 80 | rpc OperateCertificates(IdentityCertificateRequest) returns (IdentityCertificateResponse) {} 81 | 82 | // Prechecks whether the system is able to create specified identities (but does not actually create them). 83 | rpc Precheck(IdentityPrecheckRequest) returns (IdentityPrecheckResponse) {} 84 | } 85 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /rpc/cloudagent/cloud/kubernetes/moc_cloudagent_kubernetes.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/cloud"; 6 | package moc.cloudagent.kubernetes; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | 11 | message KubernetesRequest { 12 | repeated Kubernetes Kubernetess = 1; 13 | Operation OperationType = 2; 14 | } 15 | 16 | message KubernetesResponse { 17 | repeated Kubernetes Kubernetess = 1; 18 | google.protobuf.BoolValue Result = 2; 19 | string Error = 3; 20 | } 21 | 22 | message StorageConfiguration { 23 | string csi = 1; 24 | } 25 | 26 | message NetworkConfiguration { 27 | string cni = 1; 28 | string podCidr = 2; 29 | string clusterCidr = 3; 30 | // TODO: merge controlplane cidr and network 31 | string controlPlaneCidr = 4; 32 | string virtualnetwork = 5; 33 | string loadBalancerVip = 6; 34 | string loadBalancerMac = 7; 35 | } 36 | 37 | enum NodeType { 38 | ControlPlane = 0; 39 | LinuxWorker = 1; 40 | WindowsWorker = 2; 41 | LoadBalancer = 3; 42 | } 43 | 44 | enum ManagementStrategyType { 45 | Pivoted = 0; 46 | Distinct = 1; 47 | } 48 | 49 | message NodePoolConfiguration { 50 | NodeType NodeType = 1; 51 | string imagereference = 2; 52 | int32 replicas = 3; 53 | string VMSize = 4; 54 | } 55 | 56 | message SSHPublicKey { 57 | string keyData = 1 [(sensitive) = true]; 58 | } 59 | 60 | message ComputeConfiguration { 61 | string cri = 1; 62 | SSHPublicKey publicKey = 2; 63 | repeated NodePoolConfiguration NodePools = 3; 64 | } 65 | 66 | message ClusterConfiguration { 67 | string version = 1; 68 | } 69 | 70 | message ClusterAPIConfiguration { 71 | string ConfigurationEndpoint = 1; 72 | string InfrastructureProviderVersion = 2; 73 | string BootstrapProviderVersion = 3; 74 | string ControlPlaneProviderVersion = 4; 75 | string CoreProviderVersion = 5; 76 | } 77 | 78 | message ContainerRegistry { 79 | string Name = 1; 80 | string Username = 2 [(sensitive) = true]; 81 | string Password = 3 [(sensitive) = true]; 82 | } 83 | 84 | message Kubernetes { 85 | string name = 1; 86 | string id = 2; 87 | Status status = 4; 88 | ClusterConfiguration cluster = 5; 89 | NetworkConfiguration network = 6; 90 | StorageConfiguration storage = 7; 91 | ComputeConfiguration compute = 8; 92 | string groupName = 9; 93 | ManagementStrategyType managementStrategy = 10; 94 | string locationName = 11; 95 | bytes kubeConfig = 12; 96 | ClusterAPIConfiguration capiConfig = 13; 97 | ContainerRegistry containerRegistry = 14; 98 | bytes deploymentManifest = 15; 99 | Tags tags = 16; 100 | } 101 | 102 | service KubernetesAgent { 103 | rpc Invoke(KubernetesRequest) returns (KubernetesResponse) {} 104 | } 105 | 106 | -------------------------------------------------------------------------------- /rpc/mochostagent/compute/virtualmachine/moc_mochostagent_virtualmachine.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/mochostagent/compute"; 6 | package moc.mochostagent.compute; 7 | 8 | import "google/protobuf/empty.proto"; 9 | import "google/protobuf/wrappers.proto"; 10 | import "moc_common_common.proto"; 11 | import "moc_common_computecommon.proto"; 12 | import "moc_common_notification.proto"; 13 | 14 | message OperatingSystemConfiguration { 15 | OperatingSystemType ostype = 1; 16 | } 17 | 18 | message VirtualMachine { 19 | string name = 1; 20 | string id = 2; 21 | OperatingSystemConfiguration os = 3; 22 | Entity entity = 4; 23 | Tags tags = 5; 24 | VirtualMachineAgentInstanceView guestAgentInstanceView = 6; 25 | } 26 | 27 | message GetVirtualMachineResponse { 28 | VirtualMachine VirtualMachine = 1; 29 | google.protobuf.BoolValue Result = 2; 30 | string Error = 3; 31 | } 32 | 33 | message RegisterVirtualMachineRequest { 34 | VirtualMachine VirtualMachine = 1; 35 | bool waitForConnection = 2; 36 | } 37 | 38 | message RegisterVirtualMachineInstanceView { 39 | string Output = 1; 40 | string Error = 2; 41 | } 42 | 43 | message RegisterVirtualMachineResponse { 44 | VirtualMachine VirtualMachine = 1; 45 | RegisterVirtualMachineInstanceView InstanceView = 2; 46 | } 47 | 48 | message DeregisterVirtualMachineRequest { 49 | string VirtualMachineId = 1; 50 | } 51 | 52 | message DeregisterVirtualMachineInstanceView { 53 | string Output = 1; 54 | string Error = 2; 55 | } 56 | 57 | message DeregisterVirtualMachineResponse { 58 | DeregisterVirtualMachineInstanceView InstanceView = 1; 59 | } 60 | 61 | message VirtualMachineRunCommandRequest { 62 | VirtualMachine VirtualMachine = 1; 63 | VirtualMachineRunCommandScriptSource Source = 2; 64 | repeated VirtualMachineRunCommandInputParameter RunCommandInputParameters = 3; 65 | string OperationID = 4; 66 | } 67 | 68 | message VirtualMachineRunCommandResponse { 69 | VirtualMachineRunCommandInstanceView InstanceView = 1; 70 | string OperationID = 2; 71 | } 72 | 73 | message VirtualMachineRepairGuestAgentRequest { 74 | VirtualMachine VirtualMachine = 1; 75 | } 76 | 77 | message VirtualMachineRepairGuestAgentResponse { 78 | google.protobuf.BoolValue Result = 1; 79 | string Error = 2; 80 | } 81 | 82 | service VirtualMachineAgent { 83 | rpc Get(VirtualMachine) returns (GetVirtualMachineResponse) {} 84 | rpc RegisterVirtualMachine(RegisterVirtualMachineRequest) returns (RegisterVirtualMachineResponse) {} 85 | rpc DeregisterVirtualMachine(DeregisterVirtualMachineRequest) returns (DeregisterVirtualMachineResponse) {} 86 | rpc RunCommand(VirtualMachineRunCommandRequest) returns (VirtualMachineRunCommandResponse) {} 87 | rpc CheckNotification(google.protobuf.Empty) returns (NotificationResponse) {} 88 | rpc RepairGuestAgent(VirtualMachineRepairGuestAgentRequest) returns (VirtualMachineRepairGuestAgentResponse) {} 89 | } 90 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '20 6 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'go' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v3 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v2 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | - name: Autobuild 61 | uses: github/codeql-action/autobuild@v2 62 | 63 | # ℹ️ Command-line programs to run using the OS shell. 64 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 65 | 66 | # If the Autobuild fails above, remove it and uncomment the following three lines. 67 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 68 | 69 | # - run: | 70 | # echo "Run, Build Application using script" 71 | # ./location_of_script_within_repo/buildscript.sh 72 | 73 | - name: Perform CodeQL Analysis 74 | uses: github/codeql-action/analyze@v2 75 | with: 76 | category: "/language:${{matrix.language}}" 77 | -------------------------------------------------------------------------------- /pkg/validations/proxy_validation_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the Apache v2.0 license. 3 | package validations 4 | 5 | import ( 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | 10 | "github.com/microsoft/moc/pkg/certs" 11 | commonproto "github.com/microsoft/moc/rpc/common" 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func Test_ValidateProxyURL(t *testing.T) { 16 | // Empty proxy url 17 | _, err := ValidateProxyURL("") 18 | expectedResult := "parse \"\": empty url: Invalid Input" 19 | if err.Error() != expectedResult { 20 | t.Fatalf("Test_ValidateProxyURL test case failed. Expected error %s but got %s", expectedResult, err.Error()) 21 | } 22 | 23 | // Invalid proxy url 24 | _, err = ValidateProxyURL("w3proxy.netscape.com:3128") 25 | expectedResult = "Invalid proxy URL. The URL scheme should be http or https: Invalid Input" 26 | if err.Error() != expectedResult { 27 | t.Fatalf("Test_ValidateProxyURL test case failed. Expected error %s but got %s", expectedResult, err.Error()) 28 | } 29 | } 30 | 31 | func Test_TestProxyUrlConnection(t *testing.T) { 32 | caCert, _, err := certs.GenerateClientCertificate("ValidCertificate") 33 | if err != nil { 34 | t.Fatalf("%s", err.Error()) 35 | } 36 | certBytes := certs.EncodeCertPEM(caCert) 37 | caCertString := string(certBytes) 38 | 39 | parsedUrl, _ := ValidateProxyURL("http://w3proxy.netscape.com:3128") 40 | // Invalid hostname 41 | err = TestProxyUrlConnection(parsedUrl, caCertString, "") 42 | 43 | expectedResult1 := "Get \"https://mcr.microsoft.com\": proxyconnect tcp: dial tcp: lookup w3proxy.netscape.com" 44 | expectedResult2 := "no such host: Invalid Input" 45 | assert.ErrorContains(t, err, expectedResult1) 46 | assert.ErrorContains(t, err, expectedResult2) 47 | 48 | // Valid case 49 | proxy := NewProxy() 50 | defer proxy.Target.Close() 51 | parsedUrl, _ = ValidateProxyURL(proxy.Target.URL) 52 | err = TestProxyUrlConnection(parsedUrl, "", "http://www.bing.com") 53 | if err != nil { 54 | t.Fatalf("Test_TestProxyUrlConnection test case failed. %s", err.Error()) 55 | } 56 | } 57 | 58 | func Test_ValidateProxyParameters(t *testing.T) { 59 | config := commonproto.ProxyConfiguration{} 60 | proxy := NewProxy() 61 | defer proxy.Target.Close() 62 | config.HttpProxy = proxy.Target.URL 63 | config.HttpsProxy = proxy.Target.URL 64 | 65 | // valid case 66 | err := ValidateProxyParameters(&config) 67 | if err != nil { 68 | t.Fatalf("Test_ValidateProxyParameters test case failed. %s", err.Error()) 69 | } 70 | 71 | // invalid case - invalid url 72 | config.HttpProxy = "w3proxy.netscape.com:3128" 73 | err = ValidateProxyParameters(&config) 74 | expectedResult := "Invalid proxy URL. The URL scheme should be http or https: Invalid Input" 75 | if err.Error() != expectedResult { 76 | t.Fatalf("Test_ValidateProxyParameters test case failed. Expected error %s but got %s", expectedResult, err.Error()) 77 | } 78 | } 79 | 80 | // Proxy is a simple proxy server for unit tests. 81 | type Proxy struct { 82 | Target *httptest.Server 83 | } 84 | 85 | // NewProxy creates a new proxy server for unit tests. 86 | func NewProxy() *Proxy { 87 | target := httptest.NewServer(http.DefaultServeMux) 88 | return &Proxy{Target: target} 89 | } 90 | -------------------------------------------------------------------------------- /pkg/errors/codes/codes_string.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package codes 4 | 5 | import ( 6 | "strconv" 7 | ) 8 | 9 | // String returns the string representation of the MocCode 10 | func (c MocCode) String() string { 11 | switch c { 12 | case OK: 13 | return "" 14 | case NotFound: 15 | return "NotFound" 16 | case Degraded: 17 | return "Degraded" 18 | case InvalidConfiguration: 19 | return "InvalidConfiguration" 20 | case InvalidInput: 21 | return "InvalidInput" 22 | case InvalidType: 23 | return "InvalidType" 24 | case NotSupported: 25 | return "NotSupported" 26 | case AlreadyExists: 27 | return "AlreadyExists" 28 | case InUse: 29 | return "InUse" 30 | case Duplicates: 31 | return "Duplicates" 32 | case InvalidFilter: 33 | return "InvalidFilter" 34 | case Failed: 35 | return "Failed" 36 | case InvalidGroup: 37 | return "InvalidGroup" 38 | case InvalidVersion: 39 | return "InvalidVersion" 40 | case OldVersion: 41 | return "OldVersion" 42 | case OutOfCapacity: 43 | return "OutOfCapacity" 44 | case OutOfNodeCapacity: 45 | return "OutOfNodeCapacity" 46 | case OutOfMemory: 47 | return "OutOfMemory" 48 | case UpdateFailed: 49 | return "UpdateFailed" 50 | case NotInitialized: 51 | return "NotInitialized" 52 | case NotImplemented: 53 | return "NotImplemented" 54 | case OutOfRange: 55 | return "OutOfRange" 56 | case AlreadySet: 57 | return "AlreadySet" 58 | case NotSet: 59 | return "NotSet" 60 | case InconsistentState: 61 | return "InconsistentState" 62 | case PendingState: 63 | return "PendingState" 64 | case WrongHost: 65 | return "WrongHost" 66 | case PoolFull: 67 | return "PoolFull" 68 | case NoActionTaken: 69 | return "NoActionTaken" 70 | case Expired: 71 | return "Expired" 72 | case Revoked: 73 | return "Revoked" 74 | case Timeout: 75 | return "Timeout" 76 | case RunCommandFailed: 77 | return "RunCommandFailed" 78 | case InvalidToken: 79 | return "InvalidToken" 80 | case Unknown: 81 | return "Unknown" 82 | case DeleteFailed: 83 | return "DeleteFailed" 84 | case DeletePending: 85 | return "DeletePending" 86 | case FileNotFound: 87 | return "FileNotFound" 88 | case PathNotFound: 89 | return "PathNotFound" 90 | case NotEnoughSpace: 91 | return "NotEnoughSpace" 92 | case AccessDenied: 93 | return "AccessDenied" 94 | case BlobNotFound: 95 | return "BlobNotFound" 96 | case GenericFailure: 97 | return "GenericFailure" 98 | case NoAuthenticationInformation: 99 | return "NoAuthenticationInformation" 100 | case MeasurementUnitError: 101 | return "MeasurementUnitError" 102 | case QuotaViolation: 103 | return "QuotaViolation" 104 | case IPOutOfRange: 105 | return "IPOutOfRange" 106 | case VolumeNotFound: 107 | return "VolumeNotFound" 108 | case VolumeDegraded: 109 | return "VolumeDegraded" 110 | case VolumeAccessInconsistent: 111 | return "VolumeAccessInconsistent" 112 | case PreCheckFailed: 113 | return "PreCheckFailed" 114 | case ProviderNotReady: 115 | return "ProviderNotReady" 116 | case DvdDriveNotFound: 117 | return "DvdDriveNotFound" 118 | default: 119 | return "MocCode(" + strconv.FormatUint(uint64(c), 10) + ")" 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /rpc/nodeagent/storage/virtualharddisk/moc_nodeagent_virtualharddisk.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/nodeagent/storage"; 6 | package moc.nodeagent.storage; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_notification.proto"; 11 | import "google/protobuf/empty.proto"; 12 | import "moc_common_storageinfo.proto"; 13 | import "moc_common_computecommon.proto"; 14 | import "google/protobuf/descriptor.proto"; 15 | 16 | enum VirtualHardDiskType { 17 | OS_VIRTUALHARDDISK = 0; 18 | DATADISK_VIRTUALHARDDISK = 1; 19 | } 20 | 21 | message VirtualHardDiskRequest { 22 | repeated VirtualHardDisk VirtualHardDiskSystems = 1; 23 | Operation OperationType = 2; 24 | } 25 | 26 | message VirtualHardDiskResponse { 27 | repeated VirtualHardDisk VirtualHardDiskSystems = 1; 28 | google.protobuf.BoolValue Result = 2; 29 | string Error = 3; 30 | } 31 | 32 | message VirtualHardDiskOperationRequest { 33 | repeated VirtualHardDisk VirtualHardDisks = 1; 34 | VirtualHardDiskOperation OperationType = 2; 35 | } 36 | 37 | message VirtualHardDiskOperationResponse { 38 | repeated VirtualHardDisk VirtualHardDisks = 1; 39 | google.protobuf.BoolValue Result = 2; 40 | string Error = 3; 41 | } 42 | 43 | message SFSImageProperties { 44 | string catalogName = 1; 45 | string audience = 2; 46 | string version = 3; 47 | string releaseName = 4; 48 | uint32 parts = 5; 49 | string destinationDir = 6; 50 | } 51 | 52 | message LocalImageProperties { 53 | string path = 1 [(sensitive) = true]; 54 | } 55 | 56 | message CloneImageProperties { 57 | string cloneSource = 1; 58 | } 59 | 60 | message HttpImageProperties { 61 | string httpURL = 1; 62 | } 63 | 64 | message AzureGalleryImageProperties { 65 | string sasURI = 1 [(sensitive) = true]; 66 | string version = 2; 67 | } 68 | 69 | message VirtualHardDisk { 70 | string name = 1; 71 | string id = 2; 72 | string source = 3 [(sensitivejson) = true]; 73 | string path = 4 [(sensitive) = true]; 74 | // Storage container name to hold this vhd 75 | string containerName = 5; 76 | Status status = 6; 77 | int64 size = 7; 78 | bool dynamic = 8; 79 | int32 blocksizebytes = 9; 80 | int32 logicalsectorbytes = 10; 81 | int32 physicalsectorbytes = 11; 82 | int64 controllernumber = 12; 83 | int64 controllerlocation = 13; 84 | int64 disknumber = 14; 85 | string virtualmachineName = 15; 86 | string scsipath = 16; 87 | VirtualHardDiskType virtualharddisktype = 17; 88 | Entity entity = 18; 89 | Tags tags = 19; 90 | ImageSource sourceType = 20; 91 | HyperVGeneration hyperVGeneration = 21; 92 | CloudInitDataSource cloudInitDataSource = 22; 93 | DiskFileFormat diskFileFormat = 23; 94 | string TargetUrl = 24 [(sensitive) = true]; 95 | string platformDiskId = 25; 96 | } 97 | 98 | message DiskNotificationRequest { 99 | string resourceType = 1; 100 | } 101 | 102 | service VirtualHardDiskAgent { 103 | rpc Invoke(VirtualHardDiskRequest) returns (VirtualHardDiskResponse) {} 104 | rpc CheckNotification(DiskNotificationRequest) returns (NotificationResponse) {} 105 | rpc Operate(VirtualHardDiskOperationRequest) returns (VirtualHardDiskOperationResponse) {} 106 | } -------------------------------------------------------------------------------- /pkg/config/config_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the Apache v2.0 license. 3 | package config 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | 9 | "github.com/microsoft/moc/pkg/marshal" 10 | ) 11 | 12 | type SampleStruct struct { 13 | TestString string `json:"testString,omitempty" yaml:testString,omitempty"` 14 | TestString2 string `json:"testStrings,omitempty" yaml:testString,omitempty"` 15 | TestInt int `json:"testInt,omitempty" yaml:"testInt,omitempty"` 16 | TestArray []string `json:"testArray,omitempty" yaml:"testArray,omitempty"` 17 | } 18 | 19 | var tmp = SampleStruct{ 20 | TestString: "TestString", 21 | TestString2: "TestString2", 22 | TestInt: 1, 23 | TestArray: []string{"TestArray"}, 24 | } 25 | 26 | var tmpArray = []SampleStruct{ 27 | { 28 | TestString: "test1String", 29 | TestString2: "test1String2", 30 | TestInt: 1, 31 | TestArray: []string{"test1Array"}, 32 | }, 33 | { 34 | TestString: "test2String", 35 | TestString2: "test2String2", 36 | TestInt: 2, 37 | TestArray: []string{"test2Array"}, 38 | }, 39 | } 40 | 41 | func Test_LoadYAMLConfig(t *testing.T) { 42 | tmpString := `teststring: TestString 43 | testInt: 1 44 | testArray: 45 | - TestArray` 46 | 47 | tmpData := SampleStruct{} 48 | err := LoadYAMLConfig(tmpString, &tmpData) 49 | if err != nil { 50 | t.Errorf("Failed to load Yaml Config %s", err.Error()) 51 | } 52 | } 53 | func Test_PrintYAML(t *testing.T) { 54 | tmp := SampleStruct{ 55 | TestString: "TestString", 56 | TestInt: 1, 57 | TestArray: []string{"TestArray"}, 58 | } 59 | PrintYAML(tmp) 60 | } 61 | func Test_PrintJSON(t *testing.T) { 62 | PrintJSON(tmp) 63 | } 64 | func Test_PrintYAMLList(t *testing.T) { 65 | PrintYAMLList(tmpArray) 66 | } 67 | func Test_PrintJSONList(t *testing.T) { 68 | PrintJSONList(tmpArray) 69 | } 70 | func Test_PrintTable(t *testing.T) { 71 | PrintTable(tmpArray) 72 | } 73 | 74 | func Test_PrintFormat(t *testing.T) { 75 | PrintFormat(tmp, "", "tsv") 76 | PrintFormat(tmp, "", "csv") 77 | } 78 | 79 | func Test_PrintFormatList(t *testing.T) { 80 | PrintFormatList(tmpArray, "", "tsv") 81 | PrintFormatList(tmpArray, "", "csv") 82 | } 83 | 84 | func Test_MarshalOutputWithoutQuery(t *testing.T) { 85 | err := verifyMarshalOutput(tmpArray, "", 2) 86 | if err != nil { 87 | t.Errorf("MarshalOutput with empty query failed: %s", err.Error()) 88 | } 89 | } 90 | 91 | func Test_MarshalOutputWithIntQuery(t *testing.T) { 92 | err := verifyMarshalOutput(tmpArray, "[?testInt==`2`]", 1) 93 | if err != nil { 94 | t.Errorf("MarshalOutput with int query failed: %s", err.Error()) 95 | } 96 | } 97 | 98 | func Test_MarshalOutputWithStringQuery(t *testing.T) { 99 | err := verifyMarshalOutput(tmpArray, "[?testString=='test1String']", 1) 100 | if err != nil { 101 | t.Errorf("MarshalOutput with string query failed: %s", err.Error()) 102 | } 103 | } 104 | 105 | func verifyMarshalOutput(data interface{}, query string, expectedResultCount int) error { 106 | result, err := MarshalOutput(data, query, "json") 107 | if err != nil { 108 | return err 109 | } 110 | 111 | var filteredArray []SampleStruct 112 | err = marshal.FromJSONBytes(result, &filteredArray) 113 | if err != nil { 114 | return err 115 | } 116 | 117 | if len(filteredArray) != expectedResultCount { 118 | return fmt.Errorf("Unexpected result count. Expected: %d / Actual: %d", expectedResultCount, len(filteredArray)) 119 | } 120 | 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /rpc/cloudagent/network/loadbalancer/moc_cloudagent_loadbalancer.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | syntax = "proto3"; 5 | option go_package = "github.com/microsoft/moc/rpc/cloudagent/network"; 6 | package moc.cloudagent.network; 7 | 8 | import "google/protobuf/wrappers.proto"; 9 | import "moc_common_common.proto"; 10 | import "moc_common_networkcommon.proto"; 11 | 12 | message LoadBalancerRequest { 13 | repeated LoadBalancer LoadBalancers = 1; 14 | Operation OperationType = 2; 15 | ApiVersion version = 3; 16 | } 17 | 18 | message LoadBalancerResponse { 19 | repeated LoadBalancer LoadBalancers = 1; 20 | google.protobuf.BoolValue Result = 2; 21 | string Error = 3; 22 | } 23 | 24 | message LoadBalancerPrecheckRequest { 25 | repeated LoadBalancer LoadBalancers = 1; 26 | } 27 | 28 | message LoadBalancerPrecheckResponse { 29 | // The precheck result: true if the precheck criteria is passed; otherwise, false 30 | google.protobuf.BoolValue Result = 1; 31 | 32 | // The error message if the precheck is not passed; otherwise, empty string 33 | string Error = 2; 34 | } 35 | 36 | message LoadbalancerInboundNatRule { 37 | string name = 1; 38 | uint32 frontendPort = 2; 39 | uint32 backendPort = 3; 40 | Protocol protocol = 4; 41 | } 42 | 43 | message LoadbalancerOutboundNatRule { 44 | string name = 1; 45 | repeated FrontendIPConfigurationReference frontendIpConfigurationsRef= 2; 46 | BackendAddressPoolReference backendAddressPoolRef= 3; 47 | Protocol protocol = 4; 48 | bool enableTcpReset = 5; 49 | Tags tags = 6; 50 | } 51 | 52 | enum LoadDistribution { 53 | Default = 0; 54 | SourceIp = 1; 55 | SourceIPProtocol = 2; 56 | } 57 | 58 | message LoadBalancingRule { 59 | uint32 frontendPort = 1; 60 | uint32 backendPort = 2; 61 | Protocol protocol = 3; 62 | ProbeReference probeRef = 4; 63 | repeated FrontendIPConfigurationReference frontendIpConfigurationsRef= 5; 64 | BackendAddressPoolReference backendAddressPoolRef= 6; 65 | string name = 7; 66 | uint32 idleTimeoutInMinutes = 8; 67 | bool enableFloatingIP = 9; 68 | bool enableTcpReset = 10; 69 | LoadDistribution loadDistribution = 11; 70 | Tags tags = 12; 71 | } 72 | 73 | enum ProbeProtocol { 74 | Http = 0; 75 | Https = 1; 76 | Tcp = 2; 77 | } 78 | 79 | message Probe { 80 | string name = 1; 81 | uint32 intervalInSeconds = 2; 82 | uint32 numberOfProbes = 3; 83 | ProbeProtocol protocol = 4; 84 | uint32 port = 5; 85 | string requestPath = 6; 86 | Tags tags = 7; 87 | } 88 | 89 | message FrontEndIpConfiguration { 90 | string name = 1; 91 | PublicIPAddressReference publicIPAddress = 2; // required if not using privateIP and a subnet. resourceRef to publicIPAddress 92 | Tags tags = 3; 93 | } 94 | 95 | message BackendAddressPool { 96 | string name = 1; 97 | Tags tags = 2; 98 | } 99 | 100 | message LoadBalancer { 101 | string name = 1; 102 | string id = 2; 103 | string frontendIP = 3 [(sensitive) = true]; 104 | repeated string backendpoolnames = 4; 105 | string networkid = 5; 106 | repeated LoadBalancingRule loadbalancingrules = 6; 107 | string nodefqdn = 7 [(sensitive) = true]; 108 | string groupName = 8; 109 | string locationName = 9; 110 | Status status = 10; 111 | Tags tags = 11; 112 | uint32 replicationCount = 12; 113 | repeated LoadbalancerInboundNatRule inboundNatRules = 13; 114 | repeated LoadbalancerOutboundNatRule outboundNatRules = 14; 115 | repeated FrontEndIpConfiguration frontendIpConfigurations = 15; 116 | repeated Probe probes = 16; 117 | repeated BackendAddressPool backendAddressPools = 17; 118 | } 119 | 120 | service LoadBalancerAgent { 121 | rpc Invoke(LoadBalancerRequest) returns (LoadBalancerResponse) {} 122 | 123 | // Prechecks whether the system is able to create specified load balancers (but does not actually create them). 124 | rpc Precheck(LoadBalancerPrecheckRequest) returns (LoadBalancerPrecheckResponse) {} 125 | } 126 | -------------------------------------------------------------------------------- /pkg/auth/auth_env_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package auth 4 | 5 | import ( 6 | "crypto/rand" 7 | "crypto/rsa" 8 | "os" 9 | "path/filepath" 10 | "testing" 11 | ) 12 | 13 | var key *rsa.PrivateKey 14 | 15 | func init() { 16 | os.MkdirAll("/tmp/auth", os.ModePerm) 17 | key, _ = rsa.GenerateKey(rand.Reader, 2048) 18 | } 19 | 20 | func Test_GetWssdConfigLocationWssdConfigPathSet(t *testing.T) { 21 | 22 | os.Unsetenv(AccessFileDirPath) 23 | os.Setenv(WssdConfigPath, "TestWssdConfigPath") 24 | 25 | wssdConfigPath := os.Getenv(WssdConfigPath) 26 | path := GetWssdConfigLocation() 27 | expectedPath := wssdConfigPath 28 | if path != expectedPath { 29 | t.Errorf("Invalid path when ACCESSFILE_DIR_PATH is not set and WSSD_CONFIG_PATH is set! Expected %s Actual %s", expectedPath, path) 30 | } 31 | } 32 | 33 | func Test_GetWssdConfigLocationEnvNotSet(t *testing.T) { 34 | 35 | os.Unsetenv(WssdConfigPath) 36 | os.Unsetenv(AccessFileDirPath) 37 | 38 | path := GetWssdConfigLocation() 39 | wd, err := os.UserHomeDir() 40 | if err != nil { 41 | t.Errorf("Failed to get user home directory path %v", err) 42 | } 43 | execName, err := getExecutableName() 44 | if err != nil { 45 | t.Errorf("Failed to get executable name %v", err) 46 | } 47 | expectedPath := filepath.Join(wd, ".wssd", execName, "cloudconfig") 48 | if path != expectedPath { 49 | t.Errorf("Invalid path when both ACCESSFILE_DIR_PATH and WSSD_CONFIG_PATH env variables are not set! Expected %s Actual %s", expectedPath, path) 50 | } 51 | } 52 | 53 | func Test_GetWssdConfigLocationAccessFileDirPathSet(t *testing.T) { 54 | 55 | os.Setenv(AccessFileDirPath, "TestAccessFileDirPath") 56 | accessFileDirPath := os.Getenv(AccessFileDirPath) 57 | path := GetWssdConfigLocation() 58 | execName, err := getExecutableName() 59 | if err != nil { 60 | t.Errorf("Failed to get executable name %v", err) 61 | } 62 | expectedPath := filepath.Join(accessFileDirPath, execName, "cloudconfig") 63 | if path != expectedPath { 64 | t.Errorf("Invalid path when ACCESSFILE_DIR_PATH env variable is set! Expected %s Actual %s", expectedPath, path) 65 | } 66 | } 67 | 68 | func Test_GetWssdConfigLocationName(t *testing.T) { 69 | path := GetMocConfigLocationName("", "") 70 | wd, err := os.UserHomeDir() 71 | if err != nil { 72 | t.Errorf("Failed getting home path %v", err) 73 | } 74 | expectedPath := filepath.Join(wd, ".wssd/cloudconfig") 75 | if path != expectedPath { 76 | t.Errorf("Invalid path when not passed no subfolder or filename Expected %s Actual %s", expectedPath, path) 77 | } 78 | } 79 | 80 | func Test_GetWssdConfigLocationNameWithSubfolder(t *testing.T) { 81 | path := GetMocConfigLocationName("test", "") 82 | wd, err := os.UserHomeDir() 83 | if err != nil { 84 | t.Errorf("Failed getting home path %v", err) 85 | } 86 | expectedPath := filepath.Join(wd, ".wssd/test/cloudconfig") 87 | if path != expectedPath { 88 | t.Errorf("Invalid path when not passed no subfolder or filename Expected %s Actual %s", expectedPath, path) 89 | } 90 | } 91 | 92 | func Test_GetWssdConfigLocationNameWithSubfolderName(t *testing.T) { 93 | path := GetMocConfigLocationName("test", "cc") 94 | wd, err := os.UserHomeDir() 95 | if err != nil { 96 | t.Errorf("Failed getting home path %v", err) 97 | } 98 | expectedPath := filepath.Join(wd, ".wssd/test/cc") 99 | if path != expectedPath { 100 | t.Errorf("Invalid path when not passed no subfolder or filename Expected %s Actual %s", expectedPath, path) 101 | } 102 | } 103 | 104 | func Test_GetWssdConfigLocationNameWithName(t *testing.T) { 105 | path := GetMocConfigLocationName("", "cc") 106 | wd, err := os.UserHomeDir() 107 | if err != nil { 108 | t.Errorf("Failed getting home path %v", err) 109 | } 110 | expectedPath := filepath.Join(wd, ".wssd/cc") 111 | if path != expectedPath { 112 | t.Errorf("Invalid path when not passed no subfolder or filename Expected %s Actual %s", expectedPath, path) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /pkg/tags/tags_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | package tags 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/microsoft/moc/pkg/errors" 9 | common "github.com/microsoft/moc/rpc/common" 10 | ) 11 | 12 | func TestTag(t *testing.T) { 13 | tag := InitTag("testkey", "testvalue") 14 | if tag.GetKey() != "testkey" || tag.GetValue() != "testvalue" { 15 | t.Errorf("Failed to create Tag") 16 | } 17 | t.Logf("%s-%s", tag.GetKey(), tag.GetValue()) 18 | } 19 | 20 | func TestAddTag(t *testing.T) { 21 | tags := &common.Tags{} 22 | AddTag("testkey", "testvalue", tags) 23 | if len(tags.GetTags()) != 1 || tags.Tags[0].GetKey() != "testkey" || tags.Tags[0].GetValue() != "testvalue" { 24 | t.Errorf("Failed to add Tag") 25 | } 26 | t.Logf("%s-%s", tags.Tags[0].GetKey(), tags.Tags[0].GetValue()) 27 | } 28 | 29 | func TestDeleteTag(t *testing.T) { 30 | tags := &common.Tags{} 31 | AddTag("testkey", "testvalue", tags) 32 | AddTag("testkey1", "testvalue1", tags) 33 | DeleteTag("testkey", tags) 34 | if len(tags.GetTags()) != 1 || tags.Tags[0].GetKey() != "testkey1" || tags.Tags[0].GetValue() != "testvalue1" { 35 | t.Errorf("Failed to delete Tag") 36 | } 37 | 38 | _, err := GetTagValue("testkey", tags) 39 | if err == nil { 40 | t.Errorf("Failed to delete Tag") 41 | } 42 | if !errors.IsNotFound(err) { 43 | t.Errorf("DeleteTag failed") 44 | } 45 | 46 | DeleteTag("testkey2", tags) 47 | if len(tags.GetTags()) != 1 || tags.Tags[0].GetKey() != "testkey1" || tags.Tags[0].GetValue() != "testvalue1" { 48 | t.Errorf("Failed to delete Tag") 49 | } 50 | t.Logf("%s-%s", tags.Tags[0].GetKey(), tags.Tags[0].GetValue()) 51 | } 52 | 53 | func TestGetTagValue(t *testing.T) { 54 | tags := &common.Tags{} 55 | AddTag("testkey", "testvalue", tags) 56 | value, err := GetTagValue("testkey", tags) 57 | if err != nil { 58 | t.Errorf("Failed to get Tag") 59 | } 60 | if value != "testvalue" { 61 | t.Errorf("Failed to get Tag value") 62 | } 63 | t.Logf("%s", value) 64 | } 65 | 66 | func TestAddTagValue(t *testing.T) { 67 | tags := &common.Tags{} 68 | AddTag("testkey", "testvalue", tags) 69 | value, err := GetTagValue("testkey", tags) 70 | if err != nil { 71 | t.Errorf("Failed to get Tag") 72 | } 73 | if value != "testvalue" { 74 | t.Errorf("Failed to get Tag value") 75 | } 76 | AddTagValue("testkey", "testvalue1", tags) 77 | value, err = GetTagValue("testkey", tags) 78 | if err != nil { 79 | t.Errorf("Failed to get Tag") 80 | } 81 | if value != "testvalue1" { 82 | t.Errorf("Failed to get Tag value") 83 | } 84 | AddTagValue("testkey1", "testvalue1", tags) 85 | value, err = GetTagValue("testkey", tags) 86 | if err != nil { 87 | t.Errorf("Failed to get Tag") 88 | } 89 | if value != "testvalue1" { 90 | t.Errorf("Failed to get Tag value") 91 | } 92 | value, err = GetTagValue("testkey1", tags) 93 | if err != nil { 94 | t.Errorf("Failed to get Tag") 95 | } 96 | if value != "testvalue1" { 97 | t.Errorf("Failed to get Tag value") 98 | } 99 | if len(tags.GetTags()) != 2 { 100 | t.Errorf("Failed to add Tag value") 101 | } 102 | t.Logf("%s", value) 103 | } 104 | 105 | func TestProtoToMap(t *testing.T) { 106 | tags := &common.Tags{} 107 | AddTagValue("testkey", "testvalue", tags) 108 | AddTagValue("testkey1", "testvalue1", tags) 109 | if len(tags.GetTags()) != 2 { 110 | t.Errorf("Failed to add Tag value") 111 | } 112 | tmap := ProtoToMap(tags) 113 | if *tmap["testkey"] != "testvalue" { 114 | t.Errorf("Missing key testkey") 115 | } 116 | if *tmap["testkey1"] != "testvalue1" { 117 | t.Errorf("Missing key testkey") 118 | } 119 | t.Logf("TestProtoToMap Passed") 120 | } 121 | 122 | func TestMapToProto(t *testing.T) { 123 | mtags := make(map[string]*string, 2) 124 | key := "testkey" 125 | key1 := "testkey1" 126 | value := "testvalue" 127 | value1 := "testvalue1" 128 | mtags[key] = &value 129 | mtags[key1] = &value1 130 | tags := MapToProto(mtags) 131 | if len(tags.GetTags()) != 2 { 132 | t.Errorf("Failed to add Tag value") 133 | } 134 | value, err := GetTagValue("testkey", tags) 135 | if err != nil { 136 | t.Errorf("Failed to get Tag") 137 | } 138 | if value != "testvalue" { 139 | t.Errorf("Failed to get Tag value") 140 | } 141 | value, err = GetTagValue("testkey1", tags) 142 | if err != nil { 143 | t.Errorf("Failed to get Tag") 144 | } 145 | if value != "testvalue1" { 146 | t.Errorf("Failed to get Tag value") 147 | } 148 | t.Logf("TestMapToProto Passed") 149 | } 150 | -------------------------------------------------------------------------------- /pkg/auth/pkv.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package auth 5 | 6 | import ( 7 | "crypto/sha256" 8 | "crypto/x509" 9 | "encoding/hex" 10 | "strings" 11 | 12 | "github.com/pkg/errors" 13 | ) 14 | 15 | const ( 16 | // formatSHA256 is the prefix for pins that are full-length SHA-256 hashes encoded in base 16 (hex) 17 | formatSHA256 = "sha256" 18 | ) 19 | 20 | type publicKeyVerifier struct { 21 | pubkeypinSet *Set 22 | } 23 | 24 | func NewPublicKeyVerifier() *publicKeyVerifier { 25 | pkv := &publicKeyVerifier{} 26 | pkv.pubkeypinSet = NewSet() 27 | return pkv 28 | } 29 | 30 | func (pkv *publicKeyVerifier) Allow(caCertHash string) error { 31 | return pkv.pubkeypinSet.Allow(caCertHash) 32 | } 33 | 34 | // VerifyPeerCertificate is a callback to be used for client verification during the TLS handshake 35 | func (c *publicKeyVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 36 | 37 | x509certs := []*x509.Certificate{} 38 | 39 | for _, crt := range rawCerts { 40 | x509cert, err := x509.ParseCertificate(crt) 41 | if err != nil { 42 | return errors.Wrapf(err, "bad server certificate") 43 | } 44 | x509certs = append(x509certs, x509cert) 45 | } 46 | 47 | err := c.pubkeypinSet.CheckAny(x509certs) 48 | if err != nil { 49 | return err 50 | } 51 | return nil 52 | } 53 | 54 | // NB. This is taken from kubeadm https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/util/pubkeypin/pubkeypin.go 55 | // Bringing the moc pkgs are light on dependencies and didn't want to muck that up for a self concerned pkg. 56 | // Also this gives us freedom to tweak to our usecase 57 | 58 | // Set is a set of pinned x509 public keys. 59 | type Set struct { 60 | sha256Hashes map[string]bool 61 | } 62 | 63 | // NewSet returns a new, empty PubKeyPinSet 64 | func NewSet() *Set { 65 | return &Set{make(map[string]bool)} 66 | } 67 | 68 | // Allow adds an allowed public key hash to the Set 69 | func (s *Set) Allow(pubKeyHashes ...string) error { 70 | for _, pubKeyHash := range pubKeyHashes { 71 | parts := strings.Split(pubKeyHash, ":") 72 | if len(parts) != 2 { 73 | return errors.New("invalid public key hash, expected \"format:value\"") 74 | } 75 | format, value := parts[0], parts[1] 76 | 77 | switch strings.ToLower(format) { 78 | case "sha256": 79 | return s.allowSHA256(value) 80 | default: 81 | return errors.Errorf("unknown hash format %q", format) 82 | } 83 | } 84 | return nil 85 | } 86 | 87 | // CheckAny checks if at least one certificate matches one of the public keys in the set 88 | func (s *Set) CheckAny(certificates []*x509.Certificate) error { 89 | var hashes []string 90 | 91 | for _, certificate := range certificates { 92 | if s.checkSHA256(certificate) { 93 | return nil 94 | } 95 | 96 | hashes = append(hashes, Hash(certificate)) 97 | } 98 | return errors.Errorf("none of the public keys %q are pinned", strings.Join(hashes, ":")) 99 | } 100 | 101 | // Hash calculates the SHA-256 hash of the Subject Public Key Information (SPKI) 102 | // object in an x509 certificate (in DER encoding). It returns the full hash as a 103 | // hex encoded string (suitable for passing to Set.Allow). 104 | func Hash(certificate *x509.Certificate) string { 105 | spkiHash := sha256.Sum256(certificate.RawSubjectPublicKeyInfo) 106 | return formatSHA256 + ":" + strings.ToLower(hex.EncodeToString(spkiHash[:])) 107 | } 108 | 109 | // allowSHA256 validates a "sha256" format hash and adds a canonical version of it into the Set 110 | func (s *Set) allowSHA256(hash string) error { 111 | // validate that the hash is the right length to be a full SHA-256 hash 112 | hashLength := hex.DecodedLen(len(hash)) 113 | if hashLength != sha256.Size { 114 | return errors.Errorf("expected a %d byte SHA-256 hash, found %d bytes", sha256.Size, hashLength) 115 | } 116 | 117 | // validate that the hash is valid hex 118 | _, err := hex.DecodeString(hash) 119 | if err != nil { 120 | return err 121 | } 122 | 123 | // in the end, just store the original hex string in memory (in lowercase) 124 | s.sha256Hashes[strings.ToLower(hash)] = true 125 | return nil 126 | } 127 | 128 | // checkSHA256 returns true if the certificate's "sha256" hash is pinned in the Set 129 | func (s *Set) checkSHA256(certificate *x509.Certificate) bool { 130 | actualHash := sha256.Sum256(certificate.RawSubjectPublicKeyInfo) 131 | actualHashHex := strings.ToLower(hex.EncodeToString(actualHash[:])) 132 | return s.sha256Hashes[actualHashHex] 133 | } 134 | -------------------------------------------------------------------------------- /.pipelines/static.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: StaticAnalysis 3 | 4 | pool: 5 | vmImage: 'windows-latest' 6 | 7 | variables: 8 | - group: moc-build 9 | - name: GO111MODULE 10 | value: 'on' 11 | - name: LGTM.UploadSnapshot 12 | value: true 13 | 14 | steps: 15 | - task: InstallSSHKey@0 16 | inputs: 17 | knownHostsEntry: '$(KNOWN_HOST)' 18 | sshPublicKey: '$(SSH_PUBLIC_KEY)' 19 | sshKeySecureFile: 'azure-pipelines-ssh-key-new' 20 | - script: | 21 | git config --global url.ssh://git@github.com/.insteadOf https://github.com/ 22 | git config --global url."msazure@vs-ssh.visualstudio.com:v3".insteadOf https://msazure.visualstudio.com 23 | displayName: 'Set up the Go workspace' 24 | 25 | - task: NodeTool@0 26 | inputs: 27 | versionSpec: '14.x' 28 | 29 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-codeinspector.CodeInspector@2 30 | displayName: 'Run Code Inspector' 31 | inputs: 32 | ProductId: 0 33 | continueOnError: true 34 | 35 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3 36 | displayName: Credential Scan 37 | inputs: 38 | outputFormat: pre 39 | batchSize: 20 40 | debugMode: false 41 | continueOnError: true 42 | 43 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@2 44 | displayName: 'Run PoliCheck' 45 | inputs: 46 | targetType: F 47 | result: PoliCheck.xml 48 | optionsFC: 0 49 | optionsXS: 0 50 | optionsHMENABLE: 0 51 | continueOnError: true 52 | 53 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-gosec.GoSec@1 54 | displayName: 'Run GoSec' 55 | inputs: 56 | targetPattern: guardianGlob 57 | continueOnError: true 58 | 59 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-semmle.Semmle@1 60 | env: 61 | SYSTEM_ACCESSTOKEN: $(System.AccessToken) 62 | displayName: 'Run CodeQL (Semmle)' 63 | inputs: 64 | language: 'go' 65 | buildCommandsString: 'make all' 66 | continueOnError: true 67 | condition: succeededOrFailed() 68 | 69 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@2 70 | displayName: 'Create Security Analysis Report' 71 | inputs: 72 | GdnExportTsvFile: true 73 | GdnExportHtmlFile: true 74 | GdnExportOutputBaselineFile: myBaseline 75 | GdnExportOutputBaseline: myBaselinedResults 76 | GdnExportOutputSuppressionFile: mySuppressions 77 | GdnExportOutputSuppressionSet: mySuppressionSet 78 | GdnExportPolicyMinSev: Warning 79 | GdnExportGdnToolApiScanSeverity: Warning 80 | GdnExportGdnToolArmorySeverity: Warning 81 | GdnExportGdnToolBanditSeverity: Warning 82 | GdnExportGdnToolBinSkimSeverity: Warning 83 | GdnExportGdnToolCodesignValidationSeverity: Warning 84 | GdnExportGdnToolCredScanSeverity: Warning 85 | GdnExportGdnToolESLintSeverity: Warning 86 | GdnExportGdnToolFlawfinderSeverity: Warning 87 | GdnExportGdnToolFortifyScaSeverity: Warning 88 | GdnExportGdnToolFxCopSeverity: Warning 89 | GdnExportGdnToolGosecSeverity: Warning 90 | GdnExportGdnToolModernCopSeverity: Warning 91 | GdnExportGdnToolPoliCheckSeverity: Warning 92 | GdnExportGdnToolRoslynAnalyzersSeverity: Warning 93 | GdnExportGdnToolSDLNativeRulesSeverity: Warning 94 | GdnExportGdnToolSemmleSeverity: Warning 95 | GdnExportGdnToolSpotBugsSeverity: Warning 96 | GdnExportGdnToolTSLintSeverity: Warning 97 | continueOnError: true 98 | condition: succeededOrFailed() 99 | 100 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 101 | displayName: 'Publish Security Analysis Logs' 102 | continueOnError: true 103 | condition: succeededOrFailed() 104 | 105 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-uploadtotsa.TSAUpload@2 106 | displayName: 'TSA upload to Codebase: TSATest_1ES Stamp: TSA' 107 | inputs: 108 | GdnPublishTsaOnboard: true 109 | GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' 110 | continueOnError: true 111 | 112 | - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@2 113 | displayName: 'Post Analysis' 114 | inputs: 115 | GdnBreakPolicyMinSev: Warning 116 | continueOnError: false 117 | condition: succeededOrFailed() 118 | -------------------------------------------------------------------------------- /pkg/auth/auth_env.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package auth 5 | 6 | import ( 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | ClientTokenName = ".token" 14 | ClientCertName = "wssd.pem" 15 | ClientTokenPath = "WSSD_CLIENT_TOKEN" 16 | WssdConfigPath = "WSSD_CONFIG_PATH" 17 | AccessFileDirPath = "ACCESSFILE_DIR_PATH" 18 | DefaultWSSDFolder = ".wssd" 19 | AccessFileDefaultName = "cloudconfig" 20 | ) 21 | 22 | func getExecutableName() (string, error) { 23 | execPath, err := os.Executable() 24 | if err != nil { 25 | return "", err 26 | } 27 | return strings.TrimSuffix(filepath.Base(execPath), filepath.Ext(execPath)), nil 28 | } 29 | 30 | // SetCertificateDirPath sets the directory path where the client certificate will be stored 31 | // This is achieved by setting ACCESSFILE_DIR_PATH environment variable 32 | // The path is appended with the executable name before the certificate is stored 33 | func SetCertificateDirPath(certificateDirPath string) error { 34 | return os.Setenv(AccessFileDirPath, certificateDirPath) 35 | } 36 | 37 | // SetCertificateFilePath sets the file path where the client certificate will be stored 38 | // This is achieved by setting WSSD_CONFIG_PATH environment variable 39 | func SetCertificateFilePath(certificateFilePath string) error { 40 | return os.Setenv(WssdConfigPath, certificateFilePath) 41 | } 42 | 43 | // SetLoginTokenPath sets the path where the login yaml will be stored 44 | // This is achieved by setting WSSD_CLIENT_TOKEN environment variable 45 | // The path is appended with the executable name before the certificate is stored 46 | func SetLoginTokenPath(loginConfigPath string) error { 47 | return os.Setenv(ClientTokenPath, loginConfigPath) 48 | } 49 | 50 | // GetCertificateDirPath will return the directory path where the client certificate will be stored 51 | func GetCertificateDirPath() string { 52 | return os.Getenv(AccessFileDirPath) 53 | } 54 | 55 | // GetCertificateFilePath will return the file path where the client certificate will be stored 56 | func GetCertificateFilePath() string { 57 | return os.Getenv(WssdConfigPath) 58 | } 59 | 60 | // GetLoginTokenPath will return the file path where the login yaml will be stored 61 | func GetLoginTokenPath() string { 62 | return os.Getenv(ClientTokenPath) 63 | } 64 | 65 | // GetWssdConfigLocation gets the path for access file from environment 66 | func GetWssdConfigLocation() string { 67 | accessFileDirPath := os.Getenv(AccessFileDirPath) 68 | wssdConfigPath := os.Getenv(WssdConfigPath) 69 | defaultPath := accessFileDirPath 70 | 71 | if accessFileDirPath == "" && wssdConfigPath != "" { 72 | return wssdConfigPath 73 | } 74 | 75 | if accessFileDirPath == "" && wssdConfigPath == "" { 76 | wd, err := os.UserHomeDir() 77 | if err != nil { 78 | panic(err) 79 | } 80 | 81 | // Create the default config path and set the 82 | // env variable 83 | defaultPath = filepath.Join(wd, DefaultWSSDFolder) 84 | os.Setenv(AccessFileDirPath, defaultPath) 85 | } 86 | 87 | if execName, err := getExecutableName(); err == nil { 88 | defaultPath = filepath.Join(defaultPath, execName) 89 | } 90 | os.MkdirAll(defaultPath, os.ModePerm) //nolint:golint,errcheck 91 | accessFilePath := filepath.Join(defaultPath, AccessFileDefaultName) 92 | return accessFilePath 93 | } 94 | 95 | // GetWssdConfigLocationName gets the path for access filename from environment + subfolder with file name fileName 96 | func GetMocConfigLocationName(subfolder, filename string) string { 97 | wssdConfigPath := os.Getenv(WssdConfigPath) 98 | 99 | file := AccessFileDefaultName 100 | if filename != "" { 101 | file = filename 102 | } 103 | wd, err := os.UserHomeDir() 104 | if err != nil { 105 | panic(err) 106 | } 107 | if wssdConfigPath == "" || !strings.HasSuffix(wssdConfigPath, filepath.Join(wd, subfolder, file)) { 108 | // Create the default config path and set the 109 | // env variable 110 | defaultPath := filepath.Join(wd, DefaultWSSDFolder, subfolder) 111 | os.MkdirAll(defaultPath, os.ModePerm) //nolint:golint,errcheck 112 | wssdConfigPath = filepath.Join(defaultPath, file) 113 | os.Setenv(WssdConfigPath, wssdConfigPath) 114 | } 115 | return wssdConfigPath 116 | } 117 | 118 | func getClientTokenLocation() string { 119 | clientTokenPath := os.Getenv(ClientTokenPath) 120 | if clientTokenPath == "" { 121 | wd, err := os.UserHomeDir() 122 | if err != nil { 123 | panic(err) 124 | } 125 | 126 | // Create the default token path and set the 127 | // env variable 128 | defaultPath := filepath.Join(wd, DefaultWSSDFolder) 129 | os.MkdirAll(defaultPath, os.ModePerm) //nolint:golint,errcheck 130 | clientTokenPath = filepath.Join(defaultPath, ClientTokenName) 131 | os.Setenv(ClientTokenPath, clientTokenPath) 132 | } 133 | return clientTokenPath 134 | } 135 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the Apache v2.0 license. 3 | 4 | package config 5 | 6 | import ( 7 | "fmt" 8 | "io/ioutil" 9 | "reflect" 10 | 11 | "github.com/jmespath/go-jmespath" 12 | "github.com/microsoft/moc/pkg/marshal" 13 | ) 14 | 15 | // Load the virtual machine configuration from the specified path 16 | func LoadYAMLFile(path string, outData interface{}) (err error) { 17 | err = marshal.FromYAMLFile(path, outData) 18 | if err != nil { 19 | return 20 | } 21 | 22 | return 23 | } 24 | 25 | // Load the virtual machine configuration from the specified path 26 | func LoadYAMLConfig(data string, outData interface{}) (err error) { 27 | err = marshal.FromYAMLString(data, outData) 28 | if err != nil { 29 | return 30 | } 31 | 32 | return 33 | } 34 | 35 | // PrintYAML 36 | func PrintYAML(data interface{}) { 37 | str, err := marshal.ToYAML(data) 38 | if err != nil { 39 | return 40 | } 41 | fmt.Printf("%s", str) 42 | } 43 | 44 | // PrintYAMLList 45 | func PrintYAMLList(datasets interface{}) { 46 | items := reflect.ValueOf(datasets) 47 | if items.Kind() == reflect.Slice { 48 | for i := 0; i < items.Len(); i++ { 49 | PrintYAML(items.Index(i).Interface()) 50 | } 51 | } 52 | } 53 | 54 | // PrintJSON 55 | func PrintJSON(data interface{}) { 56 | str, err := marshal.ToJSON(data) 57 | if err != nil { 58 | return 59 | } 60 | fmt.Printf("%s", str) 61 | } 62 | 63 | // PrintJSONList 64 | func PrintJSONList(datasets interface{}) { 65 | items := reflect.ValueOf(datasets) 66 | if items.Kind() == reflect.Slice { 67 | for i := 0; i < items.Len(); i++ { 68 | PrintJSON(items.Index(i).Interface()) 69 | } 70 | } 71 | } 72 | 73 | func printHeader(data reflect.Value) { 74 | item := reflect.Indirect(data) 75 | for i := 0; i < item.NumField(); i++ { 76 | // For now, printing only string elements 77 | if item.Field(i).Kind() == reflect.String { 78 | fmt.Printf("%s ", item.Type().Field(i).Name) 79 | } 80 | } 81 | fmt.Println() 82 | } 83 | 84 | func printElement(data reflect.Value) { 85 | items := reflect.Indirect(data) 86 | for i := 0; i < items.NumField(); i++ { 87 | // For now, printing only string elements 88 | if items.Field(i).Kind() == reflect.String { 89 | fmt.Printf("%s ", items.Field(i).Interface()) 90 | } 91 | } 92 | fmt.Println() 93 | } 94 | 95 | // PrintTable 96 | func PrintTable(datasets interface{}) { 97 | items := reflect.ValueOf(datasets) 98 | if items.Kind() == reflect.Slice && items.Len() > 0 { 99 | printHeader(items.Index(0)) 100 | for i := 0; i < items.Len(); i++ { 101 | printElement(items.Index(i)) 102 | } 103 | } 104 | 105 | } 106 | 107 | // Load the secret configuration from the specified path 108 | func LoadValueFile(path string) (*string, error) { 109 | contents, err := ioutil.ReadFile(path) 110 | if err != nil { 111 | return nil, err 112 | } 113 | value := string(contents) 114 | 115 | return &value, nil 116 | } 117 | 118 | func ExportFormatList(datasets interface{}, path string, query string, outputType string) error { 119 | var fileToWrite string 120 | 121 | marshaledByte, err := MarshalOutput(datasets, query, outputType) 122 | if err != nil { 123 | fmt.Printf("%v", err) 124 | return err 125 | } 126 | fileToWrite += string(marshaledByte) 127 | 128 | err = ioutil.WriteFile( 129 | path, 130 | []byte(fileToWrite), 131 | 0644) 132 | return err 133 | } 134 | 135 | func PrintFormat(data interface{}, query string, outputType string) { 136 | marshaledByte, err := MarshalOutput(data, query, outputType) 137 | if err != nil { 138 | fmt.Printf("%v", err) 139 | return 140 | } 141 | fmt.Printf("%s\n", string(marshaledByte)) 142 | } 143 | 144 | func PrintFormatList(datasets interface{}, query string, outputType string) { 145 | PrintFormat(datasets, query, outputType) 146 | } 147 | 148 | func MarshalOutput(data interface{}, query string, outputType string) ([]byte, error) { 149 | var queryTarget interface{} 150 | var result interface{} 151 | var err error 152 | 153 | jsonByte, err := marshal.ToJSONBytes(data) 154 | if err != nil { 155 | return nil, err 156 | } 157 | marshal.FromJSONBytes(jsonByte, &queryTarget) //nolint:golint,errcheck 158 | if query != "" { 159 | result, err = jmespath.Search(query, queryTarget) 160 | if err != nil { 161 | return nil, err 162 | } 163 | } else { 164 | result = queryTarget 165 | } 166 | 167 | var marshaledByte []byte 168 | if outputType == "json" { 169 | marshaledByte, err = marshal.ToJSONBytes(result) 170 | } else if outputType == "ppjson" { 171 | marshaledByte, err = marshal.ToPrettyPrintedJSONBytes(result) 172 | } else if outputType == "tsv" { 173 | marshaledByte, err = marshal.ToTSVBytes(result) 174 | } else if outputType == "csv" { 175 | marshaledByte, err = marshal.ToCSVBytes(result) 176 | } else { 177 | marshaledByte, err = marshal.ToYAMLBytes(result) 178 | } 179 | 180 | if err != nil { 181 | return nil, err 182 | } 183 | 184 | return marshaledByte, nil 185 | } 186 | --------------------------------------------------------------------------------